链表中环的入口节点

来源:互联网 发布:数控龙门铣编程视频 编辑:程序博客网 时间:2024/05/21 17:19

题目

一个链表中包含环,请找出该链表的环的入口结点。

思路

使用快慢指针,快指针每次移动两格,慢指针每次移动1格,他们同时从链表的头开始出发,由于链表中有环,那么在环中经过若干次绕圈后快慢指针会相遇,这个时候再用一个指针指向头节点,一个指针指向相遇的节点,两个节点同时向后移动,当他们相遇的时候就是环的入口节点。
用数学式子证明一下为什么这样:
假设链表的头到环的入口的距离为d,环的长度为r,慢指针走的距离为s,那么快指针走的距离就是2s,假设快慢指针相遇时,慢指针在环里面已经绕了i圈,快指针绕了j圈,并且他们在环里面相遇的位置是从环入口继续往下走的l步,那么就有:
s = d + r * i + l ———–(1)
2s = d + r * j + l ——— (2)
(1)式乘2减去2式得到:
0 = d + r * (2 * i - j) + l,这个式子变形一下:
l + d = r * (j - 2 * i),根据前面的定义可以知道l是目前指针在圈里面走的步数,那么这个式子也可以理解为,目前在圈里的这个指针,再继续走d步的话,那么正好是走完了j - 2 * i个圈,不管这个j - 2 * i是多少,可以肯定的是,这个时候指针肯定是在入口。所以使用另外一个指针来从头移动到入口,这个时候确保圈里面的指针是走了d步,那么他们一定会相遇,并且相遇的地方就是环的入口。

参考代码

/*struct ListNode {    int val;    struct ListNode *next;    ListNode(int x) :        val(x), next(NULL) {    }};*/class Solution{public:    ListNode* EntryNodeOfLoop(ListNode* pHead)    {        if (!pHead->next) return nullptr;        ListNode* fast = pHead;        ListNode* slow = pHead;        fast = fast->next->next;        slow = slow->next;        while (slow != fast)        {            slow = slow->next;            fast = fast->next->next;        }        ListNode* entry = pHead;        while (entry != slow)        {            slow = slow->next;            entry = entry->next;        }        return entry;    }};
原创粉丝点击