二分法
使用前提:有序的数组
704. 二分查找
重难点::控制循环不变量,使用左闭右开时,right = size,修改时为right = mid,因为right取不到,对应mid也取不到,使用左闭右闭,right = size - 1,修改时为right = mid - 1;
35.搜索插入位置
重难点:704题的升级,关键在于分析插入位置:在最左侧和最右侧的情况,在中间的情况。 注意:当使用左闭右开时,插入位置即循环退出条件left和right相等的时候,而左闭右闭时,插入位置为left,因为right可能小于left。
34. 在排序数组中查找元素的第一个和最后一个位置
重难点:
- 和上面两题不同,这个题在找到target时不退出,而是继续循环直到找到左右边界。
- 分情况讨论,元素存在时,元素不存在时分为两种,(不存在时左右边界初始值必然没有被修改) 左右边界怎么找? 找右边界就跟着left走,因为left是不断向右走的(当left因为找到target改变时,其实它的右侧全是大于等于target的元素,左边的target不用管了,这也可以理解为什么跟着left找右边界),循环退出时,刚好是右边界,此时left在右边界下一个元素,返回时别忘了 - 1,左边界同理。但是左闭右开时,左边界刚好是左边界不用-1,因为退出条件是left <right,两者相等时就退出了 为加深理解用了两种方法都写了下(左闭右开和左闭右闭) 左闭右开:
vector<int> searchRange(vector<int>& nums, int target) {
int left_border = get_border_index(nums, target, false);
int right_border = get_border_index(nums, target, true);
if (left_border == -2 || right_border == -2) {
return {-1,-1};
}
if (right_border - left_border >= 1) {//因为开区间,所以right=mid,故right = target的位置,left在target+1位置,故可以是1
return {left_border, right_border - 1};
}
return {-1,-1};
}
左闭右闭:
vector<int> searchRange(vector<int>& nums, int target) {
int left_border = get_border_index(nums, target, false);
int right_border = get_border_index(nums, target, true);
if (left_border == -2 || right_border == -2) {
return {-1,-1};
}
if (right_border - left_border > 1) {//因为闭区间,所以right=mid - 1,故right = target - 1的位置,left在target+1位置,最少是2
return {left_border, right_border - 1};
}
return {-1,-1};
}
双指针法
27. 移除元素(快慢指针)
- 用快指针去遍历数组,遇到val时,慢指针不动,继续向前,没有遇到val,slow = fast,两者都向前移动。
977.有序数组的平方(双指针)
- 运用双指针法,因为有序数组存在负数,所以最大值一定是在两边的,最小值在中间,我们可以左右指针法,两边比较大小,然后存到新数组里,最终左右指针碰面循环结束
209.长度最小的子数组 (快慢指针)
- 快指针去遍历数组,直到走到sum大于target位置时,移动慢指针到刚好sum小于target位置,记录子数组长度,这样窗口可以始终保持最小,一趟for循环可以结束。
矩阵模拟输出
59.螺旋矩阵II (矩阵模拟输出)
- 需要保持循环不变量,怎么保持,每圈控制好startx,starty以及偏移量offect,然后就四条边挨着画就行。