力扣刷题 -- 快慢指针的常见用法 -- 找倒数N个节点,找中点,查是否有环等

快慢指针的常见用法(一般都是一个走一步,另一个走两步,走k步的走法)

ps:那些双指针一个动一个时动时不动的这里没算是快慢指针,我这里写的就是那些特别明显的,比较经典的快慢指针用法

1.查找倒数第k个节点

快的先走k步,再两个开始一起走,这样快慢中间就差了k个节点,等快的走到最后的空,那慢的自然就是倒数第k个节点

剑指 Offer 22. 链表中倒数第k个节点

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode fast=head,slow=head;
        for (int i=0;i<k;i++)
            fast=fast.next;
        while (fast!=null) {
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }
}

19. 删除链表的倒数第 N 个结点

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fast=head,slow=head;
        for (int i=0;i<n+1;i++) {
            if (fast.next==null&&i!=n) 
                return head.next;
            else
                fast=fast.next;
        }
            
        while (fast!=null) {
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        return head;
    }
}

2.查看链表是否有环

快的走两步,慢的走一步。相遇则有环。
无环:自然快的走得快,慢的跟不上。有环:快的先进到环内,当快的走到慢的后面时,假设慢的在快的前面n步,此后两个每走一次,距离就减一,所以一定会相遇。

141. 环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast=head, slow=head;
        while (fast!=null&&fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
            if (slow==fast)
                return true;
        }
        return false;
    }
}

142. 环形链表 II

这个快慢指针的解法官方题解图文并茂很清楚,不懂可看。
环形链表II力扣官方题解

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast=head, slow=head, heada=head;
        while (fast!=null&&fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow)
                break;
        }
        if (fast==null||fast.next==null) return null; //无环
        while (heada!=slow) {
            heada=heada.next;
            slow=slow.next;
        }
        return slow;
    }
}

3.找到链表中间节点

慢的走一步,快的走两步,快的到尾部的空时,慢的自然就才到中间n/2嘛,如果总数是偶数的话,是到中间的第二个。

876. 链表的中间结点

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast=head, slow=head;
        while (fast!=null&&fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
        }
        return slow;
    }
}

4.应用及其他类型

202. 快乐数
多写几个数可以发现不是快乐数的会形成环,检测有无环可以用快慢指针

class Solution {
    public boolean isHappy(int n) {
        int slow=n, fast=getNextHappyN(getNextHappyN(n));
        while (fast!=1&&fast!=slow) {
            slow=getNextHappyN(slow);
            fast=getNextHappyN(getNextHappyN(fast));
        }
        return fast==1;
    }
    public static int getNextHappyN(int n) {
        int next=0;
        while (n!=0) {
            next+=(n%10)*(n%10);
            n/=10;
        }
        return next;
    }
}

234. 回文链表
先找到中间,由中间向两边展开判断,同时需要把有半段反转

class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode fast=head, slow=head;
        //找到中间节点
        while(fast!=null&&fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
        }
        //从中间开始反转链表
        ListNode temp,pre=null;
        while(slow!=null) {
            temp=slow.next;
            slow.next=pre;
            pre=slow;
            slow=temp;
        }
        //开始比较
        while(pre!=null&&head!=null) {
            if (pre.val!=head.val)
                return false;
            pre=pre.next;
            head=head.next;
        }
        return true;

    }
}

160. 相交链表
也不完全算是快慢指针吧。不过解法倒挺好理解,各自出发,走到头后换路,相交的部分都走过一遍,各自的不相交的部分也走过一遍,走的路一样多,可不就相遇了吗

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA==null||headB==null)   return null;
        ListNode pa=headA, pb=headB;
        while (true) {
            if (pa==pb) return pa;
            if (pa.next==null&&pb.next==null) return null;
            pa=pa.next==null ? headB:pa.next;
            pb=pb.next==null ? headA:pb.next;
        }
        
    }
}

143. 重排链表
重排链表不属于上面三种类型,但也是要用到快慢指针,这个快慢指针用来拆分原链表,还是比较好想到的

下面两个不是特别明显的快慢指针,比如,一个一步步往前动,一个时动时不动:
283. 移动零
26. 删除有序数组中的重复项
等等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值