1. 有序数组添加元素
先找到要插入元素的位置,然后将这个位置包括之后的元素都后移一位,然后插入元素进入数组。首先需要判断当前数组能不能继续添加元素。
/**
* 插入指定位置元素
*
* @param arr 有序数组
* @param size 已经存储的元素数量,从1开始
* @param element 插入的元素
* @return
*/
public static int addByElement(int[] arr, int size, int element) {
// size从1开始表示实际个数,arr.length也是从1开始
if (size >= arr.length) {
return -1;
}
// 防止插入的数大于当前最大值
int index = size;
for (int i = 0; i < size; i++) {
if (element < arr[i]) {
index = i;
break;
}
}
// j开始元素都后移
for (int j = size; j > index; j--) {
arr[j] = arr[j - 1];
}
// 插入元素
arr[index] = element;
return index;
}
2. 删除指定位置元素
先找到删除元素所存在的位置,如果位置存在,记录下来,然后判断这个位置下标是不是-1.不是-1表示存在,然后将删除元素后面的元素都前移。
/**
* 删除元素key
*
* @param arr 数组
* @param size 数组元素个数从1开始
* @param key 删除元素
* @return
*/
public static int removeByElement(int[] arr, int size, int key) {
if (size >= arr.length) {
return -1;
}
// index是-1,表示不存在
int index = -1;
for (int i = 0; i < size; i++) {
if (arr[i] == key) {
index = key;
break;
}
}
if (index != -1) {
for (int i = index + 1; i < size; i++) {
arr[i - 1] = arr[i];
size--;
}
}
return size;
}
3. 单调数列
单调数列
如果数组是单调递增或单调递减的,那么它是 单调 的。
如果对于所有 i <= j,nums[i] <= nums[j],那么数组 nums 是单调递增的。 如果对于所有 i <= j,nums[i]> = nums[j],那么数组 nums 是单调递减的。
当给定的数组 nums 是单调数组时返回 true,否则返回 false。
3.1 分析
由于题目里面是包含递增和递减的,直接判断无法知道是递增还是递减,所以需要使用两个变量inc,desc来记录,如果元素都是递增的,那么最后使用inc|| desc 只会是true,一旦是fasle就表明,不是单调的。
public boolean isMonotonic(int[] nums) {
// 递增标志
boolean inc = true;
// 递减标志
boolean desc = true;
for(int i=0;i<nums.length-1;i++){
if(nums[i]>nums[i+1]){
// 由于是递减的,所以递增的不满足,设置为false
inc = false;
}
// 同理
if(nums[i] < nums[i+1]){
desc = false;
}
}
// 只要一个为true就是true,如果都是false那么就不是递增的
return inc || desc;
}
4. 搜索插入位置
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
4.1 分析
题目要求logn的时间复杂度,第一时间想到二分。
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left =0;
int right = n-1;
int ans = n;
while(left<=right){
// 这里要加上相应的括号,否则优先级会报错
int mid = ((right-left) >>1) +left;
if(target<=nums[mid]){
ans = mid;
right = mid-1;
}else{
left = mid+1;
}
}
return ans;
}
5. 合并两个有序数组
合并两个有序数组
给你两个按非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
5.1 分析
5.1.1 先将元素都添加到nums1里面去,然后对nums1排序。
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i=0;i<nums2.length;i++){
nums1[m+i] = nums2[i];
}
Arrays.sort(nums1);
}
但是很显然效率是不高的,第一此遍历nums2,时间复杂度是O(n), 第二次使用Arrays排序,底层是快排,时间复杂度是O(nlogn)
5.2.2 由于两个数组都是有序的,只需要比较两个数组的最后一个元素,将大的放入nums1的末尾,最后将未完成的元素放入nums1里面。
public static void merge(int[] nums1, int m, int[] nums2, int n) {
// 合并索引位置
int i = m + n - 1;
// nums1的最后一个元素
int len1 = m - 1;
// nums2的最后一个元素
int len2 = n - 1;
while (len1 >= 0 && len2 >= 0) {
if (nums1[len1] <= nums2[len2]) {
// 将最大的元素放入nums1的末尾
nums1[i--] = nums2[len2--];
} else {
nums1[i--] = nums1[len1--];
}
}
// 判断剩余数组是否有空余元素
while (len2 != -1) nums1[i--] = nums2[len2--];
while (len1 != -1) nums1[i--] = nums1[len1--];
}
这里面的时间复杂度就是O(m+n)两个数组的长度。可以看出效率还是很高的、
总结
数组问题的难点在于如何选择相对合理的方式来解决问题,尤其是数组的增加元素,删除元素的这种移动尤其需要注意。