什么是双指针
顾名思议,双指针就是「两个指针」,但是不同于C,C++中的指针, 其是一种「算法思想」。
如果说,我们迭代一个数组,并输出数组每一项,我们需要一个指针来记录当前遍历的项,这个过程我们叫单指针(index)的话。
(图1)
那么双指针实际上就是有两个这样的指针,最为经典的就是二分法中的左右双指针啦。
(图2)
我们发现双指针是一个很宽泛的概念,就好像数组,链表一样,其类型会有很多很多, 比如二分法经常用到左右端点双指针。滑动窗口会用到快慢指针和固定间距指针。 因此双指针其实是一种综合性很强的类型,类似于数组,栈等。。 但是我们这里所讲述的双指针,往往指的是某几种类型的双指针,而不是“只要有两个指针就是双指针了”。
那么究竟我们算法中提到的双指针指的是什么呢?我们一起来看下算法中双指针的常见题型吧。
常见题型有哪些?
这里我将其分为三种类类型,分别是:
- 快慢指针(两个指针步长不同)
- 左右端点指针(两个指针分别指向头尾,并往中间移动,步长不确定)
- 固定间距指针(两个指针间距相同,步长相同)
不管是哪一种双指针,只考虑双指针部分的话 ,由于最多还是会遍历整个数组一次,因此时间复杂度取决于步长,如果步长是1,2这种常数的话,那么时间复杂度就是O(N),如果步长是和数据规模有关(比如二分法),其时间复杂度就是O(logN)。并且由于不管规模多大,我们都只需要最多两个指针,因此空间复杂度是O(1)。下面我们就来看看双指针的常见套路有哪些。
常见套路
快慢指针
1.1. 判断链表是否有环
1.2 读写指针。典型的是
删除重复元素左右端点指针
2.1. 二分查找。
2.2. 暴力枚举中“从大到小枚举”(剪枝)find-the-longest-substring-containing-vowels-in-even
2.3 有序数组。区别于上面的二分查找,这种算法指针移动是连续的,而不是跳跃性的,典型的是LeetCode 的
两数和,以及N数和系列问题。固定间距指针
3.1 一次遍历(One Pass)求链表的中点
3.2 一次遍历(One Pass)求链表的倒数第k个元素
3.3. 固定窗口大小的滑动窗口
模板(伪代码)
- 快慢指针
l = 0
r = 0
while 没有遍历完
if 一定条件
l += 1
r += 1
return 合适的值
- 左右端点指针
l = 0
r = n - 1
while l < r
if 找到了
return 找到的值
if 一定条件1
l += 1
else if 一定条件2
r -= 1
return 没找到
- 固定间距指针
l = 0
r = k
while 没有遍历完
自定义逻辑
l += 1
r += 1
return 合适的值
题目推荐
左右端点指针
- 3Sum Closest (Medium)
- Subarray Product Less Than K (Medium)
- Squares of a Sorted Array (Easy)
- Dutch National Flag Problem
❝下面是二分类型
❞
- Search in Rotated Sorted Array (Medium)
- Koko Eating Bananas(Medium)
- Boats to Save People(Medium)
快慢指针
- Remove Duplicates from Sorted Array(Easy)
- Linked List Cycle (Easy)
- Linked List Cycle II(Medium)
- Find the Duplicate Number(Medium)
- Happy Number (Easy)
固定间距指针
- Maximum Number of Vowels in a Substring of Given Length(Medium)
❝固定窗口大小的滑动窗口见专题篇的滑动窗口专题(暂未发布)