链表经典题目:判断链表中是否存在环(二)

在前些日子的博客中,我写了链表是否有环的一道题,而今天的这道题是上一道题的升级版,不仅要确定是否有环,还需要找到环的入口点。

题目如下所示:
在这里插入图片描述
在这里插入图片描述
比如用上面的链表举例,我们要确定链表中存在环已经不是难题了,但是怎样才能确定这个环是从哪里开始的呢?

下面我通过形象一点的图示来为大家解释:
在这里插入图片描述
图中是比较形象的一个环,假设从头开始到入环口的距离是L,从入环口到相遇点的距离是X,环的周长为C。

如果链表中存在环的话,那么快指针和慢指针在环内一定会相遇,这是我在前面的博客中证明过的。要找到环的入口点,首先要找到两个指针的相遇点。找到之后,我们来计算一下,快指针和慢指针分别走的距离是多少。

慢指针走了从头节点到相遇点的距离,一共是L+X。
快指针走的距离是分为三段的,首先慢指针走到L的中间时,快指针正好走到入环的地方;当慢指针走到入环口的时候,快指针可能走了很多圈(很多人认为快指针只走了一圈,这是不对的。如果圈很小的话,当慢指针走到入环口,快指针都走了很多圈了);最后快指针又从入环口走到了相遇点。因此快指针走的距离是L+N*C+X。

由于快指针走的长度是慢指针的二倍,可以得到
2*(L+X) = L+NC+X
化简可以得到L = N
C -X。可以这样解释,当慢指针从头节点走到入环口的时候,快指针已经从入环口开始在里面转了很多圈然后走到了相遇点,因此我们有理由说从相遇点开始到入环口的距离等于从头结点走到入环口的距离。
这就是这道题的证明

代码如下:

struct ListNode *detectCycle(struct ListNode *head) {
    //设置快慢指针
    ListNode* slow = head;
    ListNode* fast = head;
    ListNode* meet = NULL;
    //要想找到环的入口点,必须使两个指针先在环内相遇
    //找相遇点
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //当两个指针相遇的时候,记录下相遇点的位置,跳出循环
        if(fast == slow)
        {
            meet = fast;
            break;
        }
    }
    //跳出循环的时候有两种情况
    //1.如果fast或者fast->next为空,表示链表无环
    if(fast ==NULL || fast->next == NULL)
        return NULL;
    //2.找到相遇点
    //经过验证,meet到入口的长度一定等于从头到入口的长度
    while(head != meet)
    {
        meet = meet->next;
        head = head->next;
    }
    return meet;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值