单向链表是否有环以及入环起点节点

本文介绍了一种检测链表是否存在环的有效方法,并给出了确定环入口节点的具体实现。通过设置两个不同速度的指针进行遍历,可以高效地解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断一个链表是否有环就有点像判断一个小数是否为循环小数。如:12.3756954756954...循环体为756954进入节点为7。如果我们从这个思路来考虑那就走远了。因为,可能这个循环体长度特别长,而这个循环体中又可能存在很多小的循环体。比如:1.1235353512791235353512791...如果我们把35当做循环体那就错了,循环体应该是123535351279。正确的思路应该是参照环形赛道跑步比赛。试想,如果赛道没有环那么即使跑无限长的时间。跑得慢的人永远看不见跑得快的。而如果是环形赛道,只要时间足够长,跑得快的迟早会追上跑的慢的。

参考:

环形追及问题公式:n=(v1-v2)*t

n:相遇时圈数,v1:1节点速度,v2:2节点速度,t:时间

作为单向链表,设两个指针 fast,slow,假设fast走2步,slow走1步。

那么

        
        ListNode slow = h;
        ListNode fast = h;
        while(fast != null && fast.next != null ){//如果跳出循环证明连表是单向的
            slow = slow.next;//1步
            fast = fast.next.next;//2步
            if(slow == fast){//快的追上慢的
                return true;
            }
        }
        return false;

如果要知道到底从哪个节点进入循环的呢?

假设相遇点到入环点的距离为x,入环段长度为a,环长r,假设相遇时fast已绕环k圈,slow已绕环n圈,(n∈N+,k∈N+且k>=n),如果fast速度是2倍于slow速度。那么n>1则k必然大于2,也就是说slow在环上每个位置都出现了一次以上了。那么fast肯定于slow相遇过(如果fast >2slow的情况不确定。)那么kr+x+a = 2(nr + x + a)此时令n=0,并且k <= 2n所以k=0

整理 r= a + x;也就是说此时碰撞点离入环点还差a,此时如果设新的两个指针,p,q同样速度,一个从起点,一个从碰撞点走,当他们下次碰撞的时候一定是入环点。

        if(h == null || h.next == null) {
            return null;
        }
        ListNode slow = h;
        ListNode fast = h;
        while(fast != null && fast.next != null ){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                ListNode p=h;
                ListNode q=slow;
                while(p != q){
                    p = p.next;
                    q = q.next;
                }
                return q;
            }
        }
        return null;

返回的q则是进入循环的节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值