【Leetcode刷题笔记之链表篇】142. 环形链表 II

😈博客主页:🐼大家好我叫张同学🐼
💖 欢迎点赞 👍 收藏 💗留言 📝 欢迎讨论! 👀
🎵本文由 【大家好我叫张同学】 原创,首发于 CSDN 🌟🌟🌟
精品专栏(不定时更新) 【数据结构+算法】 【做题笔记】【C语言编程学习】
☀️ 精品文章推荐
【C语言进阶学习笔记】三、字符串函数详解(1)(爆肝吐血整理,建议收藏!!!)
【C语言基础学习笔记】+【C语言进阶学习笔记】总结篇(坚持才有收获!)


前言

为什么要写刷题笔记
写博客的过程也是对自己刷题过程的梳理总结,是一种耗时有效的方法。
当自己分享的博客帮助到他人时,又会给自己带来额外的快乐和幸福。
(刷题的快乐+博客的快乐,简直是奖励翻倍,快乐翻倍有木有QAQ🙈)

题目内容

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next指针再次到达,则链表中存在环。
为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从0 开始)。如果 pos 是-1,则在该链表中没有环。
注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

在这里插入图片描述

原题链接(点击跳转)

思路分析
题目理解:这个题目应该拆分为两个问题:

①判断链表是否带环
②当链表带环的时候返回环的进入点

要判断链表是否带环这个问题很简单,我们可以用快慢指针的方法,当fast在环内能追上slow即带环,当fast提前走到最后一个结点或NULL则表示不带环。(有关判断链表是否带环的问题在上一篇博客中已经详细的分析和证明了,不理解或有兴趣的同学可以前往我的主页翻看上一篇博客)
但当链表带环的时候要返回环的进入点这个问题却非常麻烦,要想解决这个问题,需要借助亿点点数学技巧。(不要害怕,是很基础的数学技巧,小学的时候就学过,只是一般人很难运用数学思维去分析。)
假设环进入点之前的链表长度为L,环的长度为Cslowfast两者的相遇点与环的进入点之间的距离为X,如下图所示:
在这里插入图片描述
slow、fast开始走到两者相遇的整个过程中
slow走过的长度为:L+X
fast走过的长度为:L+nC+X(注意,fast不一定只是在环里面转了一圈,有可能转了2、3、4...n圈,n >= 1
在这里插入图片描述
因为slow一次走一步,fast一次走两步,所以fast走过的长度是slow的两倍,也就是:
L+nC+X = 2(L+X)等式两边消掉一个L+X,再将右边的X移到左边去即有:
nC-X = L 为了符合我们的阅读习惯,我们将左右换一下,也就是:
L = nC-X = (n-1)C + C-XC-X是环的长度 - 相遇点到进入点之间的长度,也就是下面这个长度:
在这里插入图片描述
也就是说链表的长度L = n-1圈的环长度 + C - X。如果我们让两个点,一个从链表起始点走,一个从相遇点meet位置走,均是每次走一步,那么这两个点必定会在环的进入点相遇。
仔细理解一下上面这句话,因为链表的长度L = (n-1)C + C - X, (n >= 1),当n=1的时候,表示两个点直接走着走着就在环入口点相遇了。(比如说你和女朋友约好去操场散步,你女朋友到操场门口的距离是L,你到操场的距离是C-X,操场的周长为C。这种情况就是你俩同时出门,一起走向操场门口,然后一起到达门口,手拉手去散步)
n >1时,从meet出发的点则会先在环里面转上 n - 1圈,然后两者在环入口点相遇(这种情况就是你女朋友离操场比较远,L比较大,虽然你俩同时往操场走,但是你先到达,你到达后没事干就在操场里面溜达几圈,然后和你女朋友在操场门口相遇)。
理解了 L = (n-1)C + C - X, (n >= 1),要写出代码,完成题目就很简单了。

函数实现
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast = head,*slow = head;
    while(fast && fast->next){
        slow = slow->next;
        fast = fast->next->next;
        if(fast == slow){
            struct ListNode *meet = slow,*cur = head;
            while(meet != cur){
                meet = meet->next;
                cur = cur->next;
            }
            return meet;
        }
    }
    return NULL;
}

在这里插入图片描述


思路分析

除了用上面的数学等式来解决外,我们还可以使用另一种方法来解决。只是这种方法在写代码的时候会比较麻烦。
假设slowfast相遇的位置为meet,将链表从相遇点meet断开,这时候就将求环进入点的问题,转化为求链表相交求交点的问题了。
在这里插入图片描述

函数实现
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *pA = headA, *pB = headB;
    while (pA != pB) {
        pA = pA == NULL ? headB : pA->next;
        pB = pB == NULL ? headA : pB->next;
    }
    return pA;
}

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast = head,*slow = head;
    while(fast && fast->next){
        slow = slow->next;
        fast = fast->next->next;
        if(fast == slow){
            struct ListNode *meet = slow,*next = slow->next,*cur = head;
            meet->next = NULL;
            return getIntersectionNode(cur,next);
        }
    }
    return NULL;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大家好我叫张同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值