剑指Offer(五十五):链表中环的入口点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HaloTrriger/article/details/80629617

链表带环是老生常谈的一个问题,链表带环衍生出了三个问题。
1. 判断链表是否带环
2. 计算环长
3. 求环的入口点
而这三个问题每个问题都建立在前一个问题的基础上才能解决。

一、判断链表是否带环
两个指针,一个fast,一个slow。从起点开始,fast一次走两步,slow一次走一步。如果它们能相遇,则链表一定带环,因为它们会在环内相遇。
二、计算环长
在上一题的基础,知道相遇点,从相遇点开始,再走一圈再回到这里的长度就是环长。
三、求环的入口点
第一种方法,知道相遇点和环长。fast从起点先走环长步,然后slow位于起点,此时它们同时一次走一步,当他们相遇时fast已经刚好走了一圈重新回到入口点,所以当他们相遇就是入口点。
代码如下:

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {}
};
ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return NULL;
        ListNode*fast = pHead;
        ListNode*slow = pHead;
        //找到快慢指针相遇点
        while (fast&&fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)
                break;
        }
        //fast走环长
        ListNode*tmp = fast;
        fast = pHead;
        while (tmp->next != slow)
        {
            tmp = tmp->next;
            fast = fast->next;
        }
        //fast补上少走的一步
        fast = fast->next;
        //同时走
        slow = pHead;
        while (fast != slow)
        {
            fast = fast->next;
            slow = slow->next;
        }
        return fast;
    }

第二种方法,知道相遇点。fast从相遇点出发,slow从起点出发,一次走一步,再次相遇的点就是入口点。(为什么再次相遇的点是入口点,后面解释)
代码如下:

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {}
};
ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return NULL;
        ListNode*fast = pHead;
        ListNode*slow = pHead;
        //快慢指针同时走,找环内相遇点
        while (fast&&fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)//链表带环
            {
                slow = pHead;
                break;
            }
        }
        //两指针此时同时一次走一步,相遇点就是入口点
        while (fast!=slow)
        {
            fast = fast->next;
            slow = slow->next;
        }
        return fast;
    }

这里解释:为什么再次相遇的点是入口点?
此处用图片直观解释
这里写图片描述

最后的最后,欢迎大家提问,有不懂的随时在线解答

猜你喜欢

转载自blog.csdn.net/HaloTrriger/article/details/80629617
今日推荐