Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Follow up:
Can you solve it without using extra space?
先用快慢指针找到它们相遇的节点,接下来快指针回到头指针,这时快慢指针保持同步走,直到相遇,此时相遇节点即为环的起始节点。
利用快慢指针判断出是否有环后,还需要找出环的起点,分析如下:
- 设链表长度为len(链表中非空next指针的个数,下面所说的长度均为非空next指针的个数),链表head到环的起点长度为a,环起点到快慢指针相遇点的长度为b,环的长度为r。
- 假设到快慢指针相遇时,慢指针移动的长度为s,则快指针移动长度为2s,而快指针移动的长度还等于s加上在环上绕的k圈(k>=1),所以2s=s+kr ,即s = kr。
- 由s = a + b 和 s = kr 可知 a + b = kr = (k-1)r + r; 而r = len - a,所以a + b = (k-1)r + len - a, 即 a = (k-1)r + len - a - b,len - a - b是相遇点到环的起点的长度,由此可知,从链表头到环起点长度 = (k-1)环长度+从相遇点到环起点长度,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇点为环起点。
struct ListNode
{
int val;
struct ListNode *next;
ListNode(int x):val(x),next(NULL){}
};
ListNode *detectCycle(ListNode *head)
{
if(head==NULL||head->next==NULL)
return NULL;
ListNode *fast=head,*low=head;
while(fast&&fast->next)
{
low=low->next;
fast=fast->next->next;
if(low==fast)//找环中快慢指针相遇节点
break;
}
if(low==fast)
{
fast=head;//快指针回到头
while(fast!=low)//快慢指针同步走
{
fast=fast->next;
low=low->next;
}
return low;//找到了环的起始节点,实际上是:a = (k-1)r + len - a - b
}else
return NULL;
}