给定一个链表,若其中包含环,则输出环的入口节点。
若其中不包含环,则输出null。
样例
给定如上所示的链表:
[1, 2, 3, 4, 5, 6]
2
注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。
则输出环的入口节点3.
算法:
用两个指针 first,second 分别从起点开始走,first 每次走一步,second 每次走两步。
如果过程中 second 走到null,则说明不存在环。否则当 first 和 second相遇后,让 first 返回起点,second 待在原地不动,然后两个指针每次分别走一步,当相遇时,相遇点就是环的入口。
公式来说明:a,b,c,x,y的含义同上,我们用 z 表示从 c 点顺时针走到 b 的距离。则第一次相遇时 second 所走的距离是x+(y+z)∗n+y, n 表示圈数,同时second 走过的距离是 first 的两倍,也就是 2(x+y),所以我们有 x+(y+z)∗n+y=2(x+y),所以 x=(n−1)×(y+z)+z。那么我们让 second从 c 点开始走,走 x 步,会恰好走到 b 点;让 first从 a 点开始走,走 x 步,也会走到 b 点。
C++代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *entryNodeOfLoop(ListNode *head) {
if (!head || !head->next) return 0;
ListNode *first = head, *second = head;
while (first && second)
{
first = first->next;
second = second->next;
if (second) second = second->next;
else return 0;
if (first == second)
{
first = head;
while (first != second)
{
first = first->next;
second = second->next;
}
return first;
}
}
return 0;
}
};