Q: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?
A: We put two points to traverse the linked list. P1 takes one step, P2 takes two step. If where is a cycle in the list , these two points will meet each other undoubtedly(see: http://blog.csdn.net/tuntunwork/article/details/38871493).
Then put two point on the linked list, one point is at the begin of the linked list , the other point is at the point where P1 and P2 meet each other. When there two points meet each other, the place is the node where the cycle begins.
Proof: We assume these is cycle in the linked list. When P1 and P2 meet each other, P1 has not traversed the whole cycle. We assume P1 has already traversed s nodes, then P2 has already traversed 2s nodes. At this time, P2 has taken more n*r steps than P1(r is the circumference of the cycle).
s + n*r = 2s
s = n*r
We assume the distance between the head of linked list and the begin of the cycle is a. And the distance between the begin of the cycle and the node where P1 and P2 meet each other is x. The length of the linked list is L.
L = a + r
a + x = s (the length which P1 has already traversed)
a + x = n * r = (n-1)*r + r = (n-1)*r + L - a
a = (n-1)*r + (L - a -x)
a%r = (L-a-x)%r
a is the distance between the head and the begin of the cycle.
L-a-x is the distance between the begin of the cycle and the node where P1 and P2 meet each other.
Based on the proof above, when P3 is at the head of the list , P4 is at the node where P1 and P2 meet each other, P3 and P4 take one step each time, the palce where P3 and P4 meet each other is the begin of the cycle(a).
ListNode *detectCycle(ListNode *head) {
if(NULL == head)
return NULL;
if(NULL == head->next)
return NULL;
if(NULL == head->next->next){
if(head == head->next->next){
return head;
}
return NULL;
}
ListNode* slow = head->next;
ListNode* fast = head->next->next;
while(NULL != fast && NULL != fast->next){
if(slow == fast)
break;
else{
slow = slow->next;
fast = fast->next->next;
}
}
if(NULL == fast || NULL == fast->next){
return NULL;
}
slow = head;
while(fast != NULL){
if(slow == fast){
return slow;
}
slow = slow->next;
fast = fast->next;
}
return NULL;
}