双指针

一、定义
双指针技巧主要分为两类:左右指针和快慢指针。所谓左右指针,就是两个指针相向而行或者相背而行;而所谓快慢指针,就是两个指针同向而行,一快一慢。
只要数组是有序的,或者是需要原地操作数组,都应该想到双指针技巧。

二、快慢指针
通常用于在有序数组/链表中去重,或者是对数组中的某些元素原地修改。
1、有序数组去重
slow指针为新数组(去重后的数组)的当前位置,而fast指针为原数组nums的当前位置。fast指针遍历原数组,当遇到新数组没有的元素就加入(即替换nums[slow] = nums[fast])slow指针向后走。因为数组是有序的,所以只需对比nums[fast]和nums[fast-1]是否相等就可以判断是否已经加入新数组(nums[fast-1]肯定比nums[fast]先加入)。
2、原地修改数组
与上题类似,slow指针为新数组(去重后的数组)的当前位置,而fast指针为原数组nums的当前位置。

3、寻找链表的倒数第k个节点

设置快慢指针起始为head,快指针先走k步(如果是删除倒数第k个节点,则先走k+1步先获取到pre节点),然后快慢指针一起走直到快指针走到末尾,此时慢指针指向的就是倒数第k个节点

4、判断链表是否成环或成环起始点

设置快慢指针起始为head,慢指针走一步,快指针就走两步,如果链表成环,快慢指针一定会再次相遇,如果快指针走到末尾都没有相遇则不成环。

如果成环,还可以求成环的起始点。两指针相遇时快指针比慢指针多走了一圈,设head到起始点为k,则一圈的长度也为k;

又设相遇点与起始点距离为m,则head到起始点 以及 相遇点运动一圈到起始点的距离都为k-m,此时将慢指针挪回head,两个指针再次相遇的地方就是起始点。

 

 

三、左右指针
前提是数组有序
例题有二分查找、两数之和、反转数组、回文串,这些题目都是比较明显可以看出需要使用左右指针的。

四、滑动窗口
滑动窗口其实是快慢指针的一种,但这里单独拿出来,是因为滑动窗口常用于求连续的子数组或子串,与前面的适用场景不同。

步骤:1、初始化窗口的左右边界left = right = 0,此时窗口是左闭右开的,包含0个元素

2、增大right来扩大窗口,直到达到要求 -- 找到可行解

3、增大left来缩小窗口,直到不满足要求,但每次增大left时,都要更新结果 -- 找到最优解
解题模板:

int left = 0, right = 0;

while (right < s.size()) {
    // 增大窗口
    window.add(s[right]);
    right++;
    
    while (window needs shrink) {
        // 缩小窗口
        window.remove(s[left]);
        left++;
    }
}

参考:labuladong 的算法小抄

posted @ 2022-09-03 23:31  陈雪佩  阅读(224)  评论(0编辑  收藏  举报