(一)二分查找
在升序数组 num[i] 中寻找目标target,返回其对应值下标 i,比较 nums[i]和 target 的大小:
如果 nums[i]=target,则下标 i为结果;
如果 nums[i]>target ,则 target只可能在下标i的左侧;
如果 nums[i]<target,则target只可能在下标i的右侧。
此为二分查找的基本原理。
二分查找的做法是,定义初始查找范围是整个数组[left,right]。每次取查找范围的中点下标值记为mid,比较 nums[mid]和target的大小,如果相等则 mid即为要寻找的下标i,如果不相等则根据 nums[mid]和 target的大小关系将mid+1或mid-1设为下次查找的left或right,查找范围缩小一半。
由于每次查找都会将查找范围缩小一半,因此二分查找的时间复杂度是 O(logn),其中 n 是数组的长度。
二分查找的条件是查找范围不为空,即 while(left<=right)。如果 target在数组中,二分查找可以保证找到 target,返回 target在数组中的下标。如果 target 不在数组中,则当 left>right 时结束查找。
(二)双指针
定义两个不同方向或不同速度的指针作为下标对数组进行访问,一半对比两个指针所对应值之间的异同解决问题,
(1)左右指针
通常在数组有序的情况下,从最小和最大端同时对数组进行处理,对满足特定条件的数组元素进行成对处理,快慢指针逐渐靠拢直至发生碰撞,则遍历完所有数组。
例如力扣27.移除元素:
此题中要求删除数组中等于 val 的元素,因此输出数组的长度一定小于等于输入数组的长度,我们可以把输出的数组直接写在输入数组上。可以使用双指针:右指针right指向当前将要处理的元素,左指针left指向下一个将要赋值的位置。
如果右指针指向的元素不等于 val 它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;
如果右指针指向的元素等于 val它不能在输出数组里,此时左指针不动,右指针右移一位。
(2)快慢指针
两个指针移动的快慢不同,通过两个指针移动速度的不同,判断判断数组和题意结果的关系
例如力扣26. 删除有序数组中的重复项
定义两个指针 fast和 slow分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标 1。
假设数组num[s]的长度为 n.将快指针fast依次遍历从 1 到 n−1的每个位置,对于每个位置,如果 nums[fast]≠nums[fast−1] 说明 nums[fast]和之前的元素都不同,因此将 nums[fast]的值复制到 nums[slow],然后将 slow值加 1,即指向下一个位置。
遍历结束之后,从 nums[0]到 nums[slow−1]的每个元素都不相同且包含原数组中的每个不同的元素,因此新的长度即为 slow。
(3)滑动窗口
滑动窗口是一种基于双指针的一种思想,两个指针指向的元素之间形成一个窗口。窗口有两类,一种是固定大小类的窗口,一类是大小动态变化的窗口.
- 初始时,左右指针left,right都指向第0个元素,窗口为[left,right),
- 循环遍历整个数组元素,判断当前right指针是否超过整个数组的长度,是退出循环,否则执行第3步
- right指针开始向右移动一个长度,窗口内数值变化。
- 窗口区间的数据满足我们的要求时,右指针right就保持不变,左指针left开始移动,直到移动到一个不再满足要求的区间时,left不再移动位置
- 再次执行第二步