双指针
1. 双指针基础知识
1. 双指针简介
双指针(Two Pointers):在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的. 如果两个指针方向相反,为对撞指针, 如果指针方向相同,称为快慢指针.如果两个指针分别属于不同的数组/链表,称为分离双指针
时间复杂度从O(n**2)降到了O(n)
2. 对撞指针
- 定义:对撞指针:两个指针left,right分别指向第一个元素和最后一个元素,然后left指针不断递增,right不断递减,直到两个指针相撞或达到其他条件为止
- 步骤:
- 使用两个指针left,right分别指向第一个元素和最后一个元素
- 在循环体中将左右指针相向移动,当满足一定条件时,将左指针右移(+1);当满足一些条件时,将右指针左移(-1)
- 直到两指针相撞或满足其他特殊条件时,跳出循环体
- 适用范围(有序数组或字符串问题):
- 查找有序数组中满足某些约束条件的一组元素问题:比如二分查找、数字之和等问题
- 字符串反转问题:反转字符串、回文数、颠倒二进制等问题
- 伪代码:
left = 0
right = len(nums) - 1
while left < right:
if 满足要求的特殊条件:
return 符合条件的值
elif 一定条件1:
left += 1
elif 一定条件2:
right -= 1
return 没找到
3. 快慢指针
- 定义:两个指针从同一侧开始遍历序列,且移动的步长一个快一个慢。移动快的指针被称为快指针(fast),移动慢的指针被称为慢指针(slow)。两个指针以不同速度、不同策略移动,直到快指针移动到数组尾端,或者两指针相交,或者满足其他特殊条件时为止。
- 步骤:
- 使用两个指针slow和fast.slow一般指向序列的第一个元素(slow = 0), fast一般指向序列的第二个元素(fast = 1)
- 在循环体中将快慢指针向右移动.当满足一定条件时,将慢指针右移(+1), 当满足另一些条件时,将快指针右移(+1)
- 到快指针移动到数组尾端(即 fast == len(nums) - 1),或者两指针相交,或者满足其他特殊条件时跳出循环体
- 适用范围:一般用于处理数组中的移动、删除元素问题,或者链表中的判断是否有环、长度问题
- 伪代码:
slow = 0
fast = 1
while 没有遍历完:
if 满足一些条件:
slow += 1
fast += 1
return ans
4. 分离双指针
- 定义:两个指针分别属于不同的数组 / 链表,两个指针分别在两个数组 / 链表中移动。
- 步骤:
- 使用两个指针left_1, left_2.left_1指向第一个数组的第一个元素(left_1 = 0),left_2指向第二个数组的第二个元素(left_2 = 0)
- 当满足一些条件时,两个指针同时右移(left_1 += 1, left_2 += 1)
- 当满足另外一些条件是,left_1右移(left_1 += 1)
- 当满足其它一些条件时,left_2右移(left_2 += 1)
- 当其中一个数组遍历完或一些其他条件时跳出循环
- 适用范围:一般用于处理有序数组合并,求交集、并集问题
- 伪代码:
left_1 = 0
left_2 = 0
while left_1 < len(nums1) and left_2 < len(nums2):
if 一定条件 1:
left_1 += 1
left_2 += 2
elif 一定条件 2:
left_1 += 1
elif 一定条件 3:
left_2 += 1
2. 滑动窗口
2.1 算法介绍
- 滑动窗口(Sliding Window):在给定数组 / 字符串上维护一个固定长度或不定长度的窗口。可以对窗口进行滑动操作、缩放操作,以及维护最优解操作。
- 操作:
- 滑动操作:窗口可按照一定方向进行移动。最常见的是向右侧移动
- 缩放操作:对于不定长度的窗口,可以从左侧缩小窗口长度,也可以从右侧增大窗口长度。
- 利用了快慢指针的技巧
2.2 适用范围:
- 一般用来解决一些查找满足一定条件的连续区间的性质(长度等)的问题
- 种类:
- 固定长度窗口
- 不定长度窗口
- 求解最大的满足条件的窗口
- 求解最小的满足条件的窗口
2.3 固定长度窗口
- 步骤:
假定窗口的固定大小为window_size- 使用两个指针 left、right。初始时,left 、right 都指向序列的第一个元素,即:left = 0,right = 0 ,区间 [left, right] 被称为一个窗口
- 当窗口未达到 window_size 大小时,不断移动 right,先将 window_size 个元素填入窗口中。
- 当窗口达到 window_size 大小时,判断窗口内的连续元素是否满足题目限定的条件
- 如果满足,再根据要求更新最优解。
- 然后向右移动 left,从而缩小窗口长度,即 left += 1,使得窗口大小始终保持为 window_size。
- 向右移动 right,将元素填入窗口中
- 重复 2 ~ 4 步,直到 right 到达序列末尾
- 伪代码实现:
left = 0
right = 0
while right < len(nums):
window.append(nums[right])
if right - left + 1 >= window_size:
window.