双指针法:一般是指的在遍历对象的过程中,不是使用单个指针进行访问,而是使用两个相同方向或者相反方向的指针进行扫描,从而达到相应的目的。

[TOC]

一、双指针法的特点

一般双指针法有以下2个优点:

1、一般在原来的内存空间上操作,很少添加额外的内存空间;

2、一般只需要循环一次,时间复杂度大幅下降。

一般双指针法有以下2种表现方式:

1、同向移动:在同向移动时,指针互相之间间隔1个距离进行移动;

2、相向移动:在相向移动中,双指针一个指针在开头,另外一个指针在结尾,根据满足的条件进行移动指针;

二、顺序结构中的双指针法

这里主要指的是数组或字符串

(1)普通数组

题目简述 关键点 解题思路 力扣题目 相关链接
删除数组中的某类元素 同向移动,快慢指针同时出发; 如果快指针遇到目标值则快指针直接跳过它一步,慢指针不动,如果快指针没有遇到目标值则将自己手中的数交给慢指针,然后各自前进一步。 27 移除元素(简单难度) https://leetcode-cn.com/problems/remove-element/
移动数组中的某类元素到开头或者末尾 同向移动,快慢指针同时出发; 如果快指针遇到目标值则快指针直接跳过它一步,慢指针不动,如果快指针没有遇到目标值则将自己手中的数和慢指针交换,然后各自前进一步。 283 移动零(简单难度) https://leetcode-cn.com/problems/move-zeroes/

(2)有序数组

提示:无序数组可以直接使用sort()函数排序后变成有序数组

题目简述 关键点 解题思路 力扣题目 相关链接
删除有序数组中的重复元素 同向移动,快指针先行一步,每次不断比较两个指针上的数是否相同。 相同则快指针直接跳过去多行一步,不相同则快指针将手中的数交给慢指针,然后快慢指针同时前进一步; 26 删除排序数组中的重复项(简单难度) https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
求有序数组中的众数(可能不止一个) 同向移动,快指针先行一步,每次不断比较两个指针上的数是否相同。 相同则频率计时器+1,不相同则频率计时器设为0;每次检查频率计时器是否超过最大技术,超过则记录当前快指针上的数为众数 169 多数元素(中等难度) https://leetcode-cn.com/problems/majority-element/
将有序数组中每个元素平方后再排序 反向移动,左指针和右指针同时出发,每次比较左指针和右指针手上的数的平方; 如果左指针手中数的平方更大则移动起始指针,如果末尾指针手中的数更大则移动末尾指针;当起始指针大于末尾指针时循环结束。(有序数组平方数组平方的最大值就在数组的两端,所以排序需要不断比较数组两端的数) 977 有序数组的平方(简单难度) https://leetcode-cn.com/problems/squares-of-a-sorted-array/

三、非顺序结构中的双指针法

这里主要指的是链表或二叉树

1、链表

链表的遍历模板

ListNode* removeElements(ListNode* head, int val) {
        //新建虚拟头结点
        ListNode * myHead = new ListNode(0);
        myHead->next=head;
        //循环检查链表的当前节点的下一节点
        ListNode* cur=myHead;//当前节点(一定不为空)
        while (cur->next != NULL) {
            if(cur->next->val == val) {
                cur->next = cur->next->next;//删除下一节点
            } else {
                cur = cur->next;//更新当前节点为下一节点
            }
        }
        //还原真实头结点
        head = myHead->next;
        return head;
    }

(1)链表的删除操作

有序链表中删除一个节点cur需要其前一个节点pre->next=cur->next; 所以其天生需要节点的先后关系。

所以在执行删除操作时,一般就需要

题目简述 关键点 解题思路 力扣题目 相关链接
删除链表中的某类元素(简单难度) 虚拟头结点;链表的循环操作和节点的删除操作 同向移动,快指针从头结点先行一步,每次判断快指针是否符合删除条件,若符合则删除快指针并且重新为快指针赋值;否则则快指针和满指针都前进一步。 203 移除链表元素(简单难度) https://leetcode-cn.com/problems/remove-linked-list-elements/
删除链表的倒数第N个节点(中等难度) 快指针先走N步之后进行判断 同向出发,快指针从头结点先行N步,如果此时快指针不存在则直接返回,若存在则快指针和慢指针(从头结点)同时出发,当快指针不存在时删除慢指针之后的一个节点。 19 删除链表的倒数第N个节点(中等难度) https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

(2)链表的反转操作

题目简述 关键点 解题思路 力扣题目 相关链接
将一个链表全部反转过来 相邻节点之间的反转操作 同向移动,快指针从头结点先行一步;每次移动快节点和慢节点都进行一次反向 206 反转链表(简单难度) https://leetcode-cn.com/problems/reverse-linked-list/
将一个链表中的[left,right]区域反转过来   慢指针从虚拟头结点出发找到第left个节点,然后快指针从慢指针的后一个节点出发,共同前进找到第right个节点 92 反转链表II(中等难度) https://leetcode-cn.com/problems/reverse-linked-list-ii/
    根据快慢指针找到中点;反转后半段;比较前后两端节点值 234 回文链表(简单难度) https://leetcode-cn.com/problems/palindrome-linked-list/

(3)环形链表的操作

题目简述 关键点 解题思路 力扣题目 相关链接
    快慢指针,若指针相遇则判断有环 141 环形链表(简单难度) https://leetcode-cn.com/problems/linked-list-cycle/
    指针环内相遇后,两个节点分别从head和相遇点出发,再次相遇点即是环入口 142 环形链表II(中等难度) https://leetcode-cn.com/problems/linked-list-cycle-ii/

(4)两条链表是否相交

题目简述 关键点 解题思路 力扣题目 相关链接
    快慢指针,若指针相遇则判断有环 141 环形链表(简单难度) https://leetcode-cn.com/problems/linked-list-cycle/
    指针环内相遇后,两个节点分别从head和相遇点出发,再次相遇点即是环入口 142 环形链表II(中等难度) https://leetcode-cn.com/problems/linked-list-cycle-ii/