链表中环的入口结点

20 篇文章 0 订阅

题目链接

链表中环的入口结点(牛客网)

题目分析

类似于追及问题:

  1. 如何判断有环的存在?
    在追及问题中,我们可以用两个速度不同的物体从同一地点出发,如果相遇则证明存在环(可用反证法证明,若不存在环,则速度不同的物体从同一地点出发则一定不会相遇),因此可以类比过来,定义两个指针fast、slow,令两指针以不同速度向后指,则相遇时证明有环存在,若fast指向NULL,则不存在环。

  2. 怎么找到环的入口结点?
    首先说方法:在问题一中两指针相遇后,让一个指针从头结点开始,另一个从相遇结点开始,并以相同速度向后指,再次相遇时就是环的入口结点。

证明:
1)假设存在环,fast以速度2运行,slow以速度1运行,在slow走到入口t时,如图(m1为在slow首次到t时fast的位置,a为h到t的距离,b为t到m1的距离,n为环的周长):
1

由图知fast走的距离为a+b+xn,slow走的距离为a,又v(fast) = 2*v(slow),所以x(fast) = 2*x(slow),即2a = a+b+xn,因此a = b+xn
m1逆时针到t的距离为n-b。

2)在首次相遇时,如图(m2为相遇点):
2

由于m1逆时针到t的距离为n-b,即要达到相遇需要追赶n-b的距离,由于两者速度差为1,因此需要n-b的时间才能相遇,此时slow再次向后n-b距离,即到达m2位置与fast相遇,因为一周长度为n,因此到t的距离为 n-(n-b) = b

3)为何令slow重新从pHead以速度1开始走,令fast从m2以速度1走?要想在入口t相遇,则需要从m2处再走b+yn的距离,刚好pHead处符合(由1)可知,同时因为是一个环,所以即使相差整数圈的距离也是在圈的同一个位置),所以令slow从pHead开始走。在相遇后就是入口t的位置。

代码

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if ( !pHead ) {
            return NULL;
        }
        
        ListNode *fast = pHead, *slow = pHead;
        while( fast && fast->next ) {
            slow = slow->next;
            fast = fast->next->next;
            if( slow == fast ) {
                slow = pHead;
                while( slow - fast ) {
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        return NULL;
    }
};
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值