力扣(LeetCode)142-环形链表Ⅱ

 题目地址:142. 环形链表 II - 力扣(LeetCode)

目录

一.解题思路

二.代码

三.思考


一.解题思路

本题是一道经典的快慢指针应用题。

大体思路如下:

让快指针和慢指针同时出发,快指针在判断链表是否循环同时。当慢指针与快指针相遇,此时再从链表头出发一个慢指针,让两个慢指针同时出发,相遇的点即是链表入环的点。

用数学来推导一下:

假设有一个环形链表,设链表头到入环点距离为L,整个环的长度为O。

 

 首先我们要知道一个基本知识:fast指针永远比slow指针多走一倍的长度,这一点贯穿始终

当slow走到入环点时,fast距离入环点的距离是x。

但fast比slow实际多走的距离是L的长度。即L = x + n * O 。(n是fast总共走过的圈数,n >= 0)

理解了这点,重点就来了:

此时,fast与slow相距O - x的距离。假设是fast追slow,那么相遇时slow走出的距离也是O - x。

此时,slow与入环点相距x的距离。

 这时,从链表头再出发一个慢指针ret,它此时与入环点相距L,即 x + n * O(n >= 0)

假设slow能与ret相遇于入环点,那么需要slow走过x + 整数个圈,即n为整数

设 x + n * O == x + v (v是slow走完x后剩余距离),解得:v == n * O。

可知,slow能走过整数个圈正好与ret相遇于入环点。

 此时,ret/slow所在点即是入环点。

二.代码

还是希望各位能先自主实现一遍。🧐

 ListNode *detectCycle(ListNode *head) {
        if(head == NULL) return head;
        ListNode* slow = head, *fast = head, *ret = head;
        while(fast && fast->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)
            {
                while(ret != slow)
                {
                    ret = ret-> next;
                    slow = slow-> next;
                }
                return ret;
            }
        }
        return NULL;
    }

三.思考

假如fast指针一次走过的距离是slow指针的3倍甚至更多,还能不能实现这个算法呢?

不一定。

原因:

fast与slow速度差的重要性主要体现在fast追slow的那一段。需要让fast能追到slow

我们不妨假设环里只有两个点:

 就会发现,当fast速度为3,slow为1时,无论如何fast都不可能追上slow!

这是因为假设fast能追上slow。那么相遇时,slow所走的距离设为s,fast所走的距离为3s,相差的2s即是O - x,那么s = (O - x) / 2。倘若O = 2, x = 1,s将不是整数,可是slow不可能走非整数,这与事实冲突。综上,当速度差为其它数时,此算法不一定成立。

 


看完麻烦三连支持一下博主吧~   如有错误,敬请斧正

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就要 宅在家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值