力扣142. 环形链表 II

前言

        昨天跟着Carl哥刷完链表的最后一章啦,今天早上睡醒写一遍笔记看看自己还能记住多少。

        每天除了上课也只能抽空跟Carl哥学一点学一点的,没想到能坚持到现在,数组和链表自己也算有基础,所以学起来并不是很费解,后面的树、图只有有一点概念而已,并没有上手写过,希望能慢慢掌握,然后像数组和链表一样自己手撕出来!

思路

        这道题无非就两个难点:1、如何判断有环?        2、如何判断环的入口?

        判断链表有无环,也是运用和数组一样的双指针法,所以就突然意识到双指针玩的好,真的能解决很多问题。

        设立一个快指针 fast 每次走两个结点,慢指针 slow 每次走一个结点。如果链表有环的话,那么快指针 fast 一定会比慢指针 slow 先一步进环内,然后在环里转圈圈,等慢指针 slow 进入环内,当快慢指针相遇时,就证明了这个链表是有环的。

        那么就有一个问题:快慢指针不会在环内错开吗?

        我们清楚快指针 fast 每次走两个结点, 而慢指针 slow 每次走一个结点,当这两个指针进入环内以后,就相当于慢指针 slow 不动,快指针每次以一个结点一个结点前进的速度去追慢指针slow,所以肯定不会错开的,这样我们也能得出两个结论:1、当慢指针进入环时,快指针一定在环内转了一圈或一圈以上。 2、快指针一定能在一圈内追上慢指针

        这是两个很重要的结论,后面也会再证明一遍。

        如果链表有环,如何判断环的入口?

        我们可以假设从头结点到环的入口距离为x,环形入口到相遇结点的长度为y,相遇节点到环形入口的长度为z

        画图相当于这样,画的很丑不过无所谓....

        我们可以得出三个公式:

  •          快指针的移动距离:x + y + n(y + z)                (n 是快指针在环内所转圈数)
  •          慢指针的移动距离:x + y
  •          快指针走过的结点数 = 2 * 慢指针走过的结点数:(x + y) * 2 = x + y + n (y + z)

        化简以后就可以得出: x = n (y + z) – y        (x就是我们要求的头结点到入口的距离)

        这里有个 -y 我们把 x 化为正数比较好,就是在 n 中提取出一圈的 (y + z)与 -y 抵消掉,化简后相当于:                        x = (n - 1)(y + z) + z

        这里证明一下 n 肯定 >= 1 的,因为快指针fast至少要多走一圈才能相遇慢指针slow,慢指针也一定是进入环形后第一圈内就被快指针追上的,如下图假设把环拉直:

        所以当 n = 1时,我们可以得出一个结论: x = z

        即:相遇位置到环入口的距离 = 头结点到环入口的距离

        跟着Carl哥得出这个,我人都麻了太顶了这个证明,有了这个证明,就可以定义两个指针,一个从相遇位置往后走,一个从头结点往后走,他们两个相遇的位置,就一定是环的入口。

        有了以上思路,我们很容易就能写出题解了。

C++代码

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode * fast = head, * slow = head;
        while(fast != NULL && fast -> next != NULL){    
            fast = fast -> next -> next;
            slow = slow -> next;
            if(fast == slow){       // 有环出现
                ListNode * index = fast, * index2 = head;
                while(index != index2){   // 找环入口
                    index = index -> next;
                    index2 = index2 -> next;
                }
                return index;
            }
        }
        return NULL;    // 链表无环返回空
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值