【91算法-基础篇】05.双指针

1,066 阅读3分钟

什么是双指针

顾名思议,双指针就是两个指针,但是不同于C,C++中的指针, 其是一种算法思想

如果说,我们迭代一个数组,并输出数组每一项,我们需要一个指针来记录当前遍历的项,这个过程我们叫单指针(index)的话。

(图1)

那么双指针实际上就是有两个这样的指针,最为经典的就是二分法中的左右双指针啦。

(图2)

我们发现双指针是一个很宽泛的概念,就好像数组,链表一样,其类型会有很多很多, 比如二分法经常用到左右端点双指针。滑动窗口会用到快慢指针和固定间距指针。 因此双指针其实是一种综合性很强的类型,类似于数组,栈等。。 但是我们这里所讲述的双指针,往往指的是某几种类型的双指针,而不是“只要有两个指针就是双指针了”。

那么究竟我们算法中提到的双指针指的是什么呢?我们一起来看下算法中双指针的常见题型吧。

常见题型有哪些?

这里我将其分为三种类类型,分别是:

  1. 快慢指针(两个指针步长不同)
  2. 左右端点指针(两个指针分别指向头尾,并往中间移动,步长不确定)
  3. 固定间距指针(两个指针间距相同,步长相同)

不管是哪一种双指针,只考虑双指针部分的话 ,由于最多还是会遍历整个数组一次,因此时间复杂度取决于步长,如果步长是1,2这种常数的话,那么时间复杂度就是O(N),如果步长是和数据规模有关(比如二分法),其时间复杂度就是O(logN)。并且由于不管规模多大,我们都只需要最多两个指针,因此空间复杂度是O(1)。下面我们就来看看双指针的常见套路有哪些。

常见套路

  1. 快慢指针

    1.1. 判断链表是否有环

    1.2 读写指针。典型的是删除重复元素

  2. 左右端点指针

    2.1. 二分查找。

    2.2. 暴力枚举中“从大到小枚举”(剪枝)find-the-longest-substring-containing-vowels-in-even

    2.3 有序数组。区别于上面的二分查找,这种算法指针移动是连续的,而不是跳跃性的,典型的是LeetCode 的两数和,以及N数和系列问题。

  3. 固定间距指针

    3.1 一次遍历(One Pass)求链表的中点

    3.2 一次遍历(One Pass)求链表的倒数第k个元素

    3.3. 固定窗口大小的滑动窗口

模板(伪代码)

  1. 快慢指针
l = 0
r = 0
while 没有遍历完
  if 一定条件
    l += 1
  r += 1
return 合适的值
  1. 左右端点指针
l = 0
r = n - 1
while l < r
  if 找到了
    return 找到的值
  if 一定条件1
    l += 1
  else if  一定条件2
    r -= 1
return 没找到

  1. 固定间距指针
l = 0
r = k
while 没有遍历完
  自定义逻辑
  l += 1
  r += 1
return 合适的值

题目推荐

左右端点指针

    1. 3Sum Closest (Medium)
    1. Subarray Product Less Than K (Medium)
    1. Squares of a Sorted Array (Easy)
  • Dutch National Flag Problem

下面是二分类型

    1. Search in Rotated Sorted Array (Medium)
    1. Koko Eating Bananas(Medium)
    1. Boats to Save People(Medium)

快慢指针

    1. Remove Duplicates from Sorted Array(Easy)
    1. Linked List Cycle (Easy)
    1. Linked List Cycle II(Medium)
    1. Find the Duplicate Number(Medium)
    1. Happy Number (Easy)

固定间距指针

    1. Maximum Number of Vowels in a Substring of Given Length(Medium)

固定窗口大小的滑动窗口见专题篇的滑动窗口专题(暂未发布)