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

xiaoxiao2021-02-28  44

链表带环是老生常谈的一个问题,链表带环衍生出了三个问题。 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; }

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

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

转载请注明原文地址: https://www.6miu.com/read-2620695.html

最新回复(0)