双指针做题总结1(碰撞指针)
例题:
三数之和:https://leetcode.cn/problems/3sum/description/?envType=study-plan-v2&envId=top-interview-150
双指针怎么用?
我们常说的「双指针」方法是,当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法,将枚举的时间复杂度从O(N^2)
减少至 O(N)。为什么是 O(N)呢?这是因为在枚举的过程每一步中,「左指针」会向右移动一个位置,而「右指针」会向左移动若干个位置,这个与数组的元素有关,但我们知道它一共会移动的位置数为 O(N),均摊下来,每次也向左移动一个位置,因此时间复杂度为 O(N))。
通俗地说,好比相遇问题,两个从数组两端开始相向而行的元素,它们相遇时行走的总路程一定为数组的长度N。
那么应当什么时候移动左指针(递增的元素)或者右指针(递减的元素)呢?
我们的目的是要分别找到合适的左右指针的下标,这里称之为解。当现在的左指针或者右指针的下标已经不可能成为解时,就继续移动该指针。
例如,三数之和问题中,第一个数A确定,第二个数B和第三个数C采用双指针枚举。那么假设左右指针在当前位置时, A + B + C > 0,此时就移动右指针。因为B只会继续增大,导致当前的C一定不会成为解。
在盛最多水的容器问题中,假设左线段比右线段低时,那么就移动左指针。因为无论怎么向左移动右线段,“短板效应”导致它们的最低线段高度都不可能再增大,此时左指针的位置一定不可能再成为解。
——————————参考————————————
总结双指针常见思路?
前面讲的方法都是针对第一种思路,即两个指针从头尾向中间移动。
- 两个指针从头尾向中间移动
这种思路一般用于有序数组中寻找两数之和、反转数组等问题。两个指针分别指向数组的头部和尾部,然后根据实际情况向中间移动,从而可以O(n)的时间复杂度解决原来需要O(n^2)的问题。
- 一快一满指针
这种方法一般用于滑动窗口类型的问题。快指针用于扩展窗口边界,满指针用于收缩窗口边界,两个指针协调配合来确定窗口大小,并对窗口内的数据进行操作。
- 同向双指针
两个指针从头或从尾出发,朝同一方向移动。这种思路一般用于寻找链表的中点、判断链表是否存在环路、移除链表中重复元素等问题。
- 反向双指针
两个指针从两端开始向中间移动,一般用于链表的反转操作。先通过一个指针遍历链表找到中点,再通过另一个指针从中点开始反转后半部分链表。
4和1有什么区别?
- 指针移动方向
- 两个指针从头尾向中间移动:两个指针分别从数组/链表的头部和尾部出发,逐步向中间移动
- 反向双指针:两个指针通常从同一端出发(头或尾),第一个指针先前进到中间位置,然后第二个指针从原点出发,与第一个指针反向而行
- 典型应用场景
- 两个指针从头尾向中间移动:常用于有序数组求和、反转数组等
- 反向双指针:常用于单链表的反转、求链表中点等
- 指针移动策略
- 两个指针从头尾向中间移动:两个指针通常保持同步移动,根据条件决定是否交换元素或执行其他操作
- 反向双指针:第一个指针先移动到中间位置,第二个指针在第一个指针的引导下反向移动,两个指针的移动策略可能不同步
- 终止条件
- 两个指针从头尾向中间移动:当两个指针相遇或错过时终止
- 反向双指针:当第二个指针移动到链表末尾或第一个指针的指定位置时终止