《剑指offer55》链表中环的入口结点c++版本

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

假设链表存在回环,如上图所示。设A为链表的起点,B为回环的起点。现在我们设定两个指针Fast(每次运动2个结点)和Slow(每次运动一个结点)。

首先我们先证明他们一定存在运动到同一点C的必然性。设AB的距离为m,BC的距离为n,环的长度为r。我们知道Fast走的长度为m+n+k1*r, Slow走的长度为m+n+k2*r,其中k1和k2为整数,又因为相同时间Fast走的距离是Slow的两倍,所以2*(m+n+k2*r)=m+n+k1*r。也就是说,m+n=(k1-2k2)*r。因为环的形状是给定的,所以m和r的值是固定的,我们必然可以找到一个n来满足上面的式子(k1和k2可以随意指定)。并且我们可以看出AC的长度m+n是环长度的整数倍。

证明了一定可以找到相遇的交点c以后,我们让Slow回到起点,保持运动速度不变。Fast留在C点,运动速度改为和Slow一样,每次运动1个结点。当Slow从A点到B的时候运动了m的长度,而此时Fast从C点向前运动(逆时针)继续运动了m,相当于从B点开始运动了m+n,正好是环的整数倍,也就是Slow和Fast相遇在了B点,正好是我们想要找的环的起点。

下面是这种方法对应的C++算法:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL){
            return NULL;
        }
        ListNode* meetingnode = MeetingNode(pHead);
        if(meetingnode == NULL){
            return NULL;
        }
        ListNode* pNode1 = meetingnode;
        // 两个指针同时移动,找到环入口
        ListNode* pNode2 = pHead;
        while(pNode1 != pNode2){
            pNode1 = pNode1->next;
            pNode2 = pNode2->next;
        }
        return pNode1;
    }
private:
    // 使用快慢指针,找到任意的一个环中结点
    ListNode* MeetingNode(ListNode* pHead){
        ListNode* pSlow = pHead->next;
        if(pSlow == NULL){
            return NULL;
        }
        ListNode* pFast = pSlow->next;
        while(pFast != NULL && pSlow != NULL){
            if(pFast == pSlow){
                return pFast;
            }
            pSlow = pSlow->next;
            pFast = pFast->next;
            if(pFast != NULL){
                pFast = pFast->next;
            }
        }
        return NULL;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值