数组:线性数据结构的一种。
数组的基础操作-一定要实践!初始与边界
单调数组
判断一个给定的数组是否为单调数组
public boolean isMonotonic(int[] nums) {boolean inc = true, dec = true;int n = nums.length;for (int i = 0; i < n - 1; ++i) {if (nums[i] > nums[i + 1]) {inc = false;}if (nums[i] < nums[i + 1]) {dec = false;}}return inc || dec;
}
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。(二分查找)
public int searchInsert(int[] nums, int target) {int n = nums.length;int left = 0, right = n - 1, 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;
}
数组合并问题
给你两个按非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 应忽略。nums2 的长度为 n 。
PS:从后向前插入,A和B的元素数量是固定的,所以排序后最远位置一定是A和B元素都最大的那个,依次类推,每次都找最大的那个从后向前填就可以了
public void merge(int[] nums1, int nums1_len, int[] nums2, int nums2_len) {int i = nums1_len + nums2_len - 1;int len1 = nums1_len - 1, len2 = nums2_len - 1;while (len1 >= 0 && len2 >= 0) {if (nums1[len1] <= nums2[len2])nums1[i--] = nums2[len2--];else if (nums1[len1] > nums2[len2])nums1[i--] = nums1[len1--];}//假如A或者B数组还有剩余while (len2 != -1) nums1[i--] = nums2[len2--];while (len1 != -1) nums1[i--] = nums1[len1--];
}
双指针类型题目
删除元素
原地删除所有数值为val的元素
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。要求:不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
1、快慢双指针
2、对撞双指针
3、对撞双指针&覆盖
删除有序数组中的重复项
给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。
1、快慢指针:一个指针负责数组遍历,一个指向有效数组的最后一个位置。
元素奇偶移动
按奇偶排序数组。给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。你可以返回满足此条件的任何数组作为答案。
1、临时数组
2、对撞双指针
数组轮转问题
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
1、连续翻转
方法如下:
-
首先对整个数组实行翻转,例如 [1,2,3,4,5,6,7] 我们先将其整体翻转成[7,6,5,4,3,2,1]。
-
从 k 处分隔成左右两个部分,这里就是根据k将其分成两组 [7,6,5] 和[4,3,2,1]。
-
最后将两个再次翻转就得到[5,6,7] 和[1,2,3,4],最终结果就是[5,6,7,1,2,3,4]
public void rotate(int[] nums, int k) {k %= nums.length;reverse(nums, 0, nums.length - 1);reverse(nums, 0, k - 1);reverse(nums, k, nums.length - 1);
}
public void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start += 1;end -= 1;}
}
数组区间问题
数组中表示的数据可能是连续的,也可能是不连续的,如果将连续的空间标记成一个区间,就是新题目。
给定一个无重复元素的有序整数数组nums。返回恰好覆盖数组中所有数字的最小有序区间范围列表。
也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。列表中的每个区间范围 [a,b] 应该按如下格式输出:"a->b" ,如果 a != b"a" ,如果 a == b
字符串替换空格问题
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
数组中只出现一次的数字
0^0 = 0;
0^a = a;
a^a = 0;
a ^ b ^ a = b.
位运算
颜色分类问题(荷兰国旗)
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。必须在不使用库的sort函数的情况下解决这个问题。
1、基于冒泡排序的双指针
2、三指针:如果要求只用一次遍历就要解决问题,该怎么办呢?我们隐约感觉到要使用三个指针才行:
-
left指针,表示left左侧的元素都是0
-
right指针 ,表示right右侧的元素都是2
-
index指针,从头到尾遍历数组,根据nums[index]是0还是2决定与left交换还是与right交换。
index位置上的数字代表着我们当前需要处理的数字。当index为数字1的时候,我们什么都不需要做,直接+1即可。如果是0,我们放到左边,如果是2,放到右边。如果index=right,则可以停止。