数组基础
数组是存放在连续内存空间上的相同类型数据的集合,我们可以方便地通过index来快速取得特定位置的数据。
数组虽然可以快速获取元素,但连续内存的存储结构也有缺点,在添加或是删除的时候需要移动后续的其他元素来达成目的。
LeetCode - 704. Binary Search 二分查找
该题旨在给定一个升序数组和一个target,如果在数组里则返回index,不存在返回-1。
大致思路就是在数组两端设定两个指针left和right,并且用target比较数组的中间数middle来不断更新left或right指针。
题目有两个容易混淆的地方,也就是left和right两个指针,还有更新左右区间时middle该不该-1,也就是边界设定的问题。边界设定一般分为[left, right) 或是 [left, right],因此确定区间的更新逻辑之前先要确定我们的边界设定。个人在这题中习惯左闭右闭的写法,因为这样左右两边更新的逻辑是一样的,不易混淆,但是要注意while中的条件left和right是要包含相等情况的。
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
if (target == nums[middle]) return middle;
if (target > nums[middle]) {
left = middle + 1; //先前已经判断过了肯定不包含middle,直接跳过middle
} else {
right = middle - 1;
}
}
return -1;
}
}
左闭右开的写法就需要注意right指针的特殊处理以及while中的条件不可取left等于right
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length;
while (left < right) {
int middle = (left + right) / 2;
if (target == nums[middle]) return middle;
if (target > nums[middle]) {
left = middle + 1;
} else {
right = middle; //right直接等于middle,因为本身区间也取不到right
}
}
return -1;
}
}
LeetCode - 27. Remove Element 移除元素
数组中移除元素时,删除的时候并不是单纯删除了这个地址位置,而是之后的元素需要一一向前补位,比如 [1,2,3,4,5] 删除元素2, 那么数组就是变成了 [1,3,4,5,_] ,至于最后一个数是什么无所谓,因为我们所需要的结果和最后一个数 无关。该题最直接的思路就是两层for循环,当第一层for循环找到目标删除元素之后再嵌套一个for循环来将之后的元素向前移动。
双指针思路主要是用fast指针来判断新数组所需要的值(即不等于我们需要删除的target的元素),把fast赋值给slow的位置,slow负责更新新数组的每一个位置,这样只要通过一次遍历并且在原数组上进行操作即可。
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}
LeetCode - 977. Squares of a Sorted Array 有序数组的平方
题目旨在给定一个升序数组,需要返回每个元素的平方且返回的数组也是升序。主要难点在于给定数组可能包含负数。我们可以抓住平方的特性,最大的平方数一定是在数组的两端,负数越小平方越大,正数越大平方越大,因此我们可以从两头开始先寻找最大值。
本题也是利用了双指针的思路,左右两边各定一个指针,分别比较两头的元素谁更大,但注意left++和right--的操作不应写在for循环条件里,因为什么时候更新哪一边需要根据比较之后谁大谁小来确定。可以忽略两边相等的情况,如果相等,那么先加左边或是右边的都不影响结果。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int update = nums.length - 1;
int right = nums.length - 1;
for (int left = 0; left <= right;) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
res[update--] = nums[left] * nums[left];
left++;
} else {
res[update--] = nums[right] * nums[right];
right--;
}
}
return res;
}
}