題目內容:
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?
解題思路:
1) 通過一快一慢兩個指針,我們可以很方便得檢測鏈表中有沒有環,只需不停向前直到兩個指針相遇即可。
到達相遇位置後,若讓單步走的指針再繞環一圈回到原點,就可以知道環的長度。這時,如果我們讓其中一個指針先走環的長度,另一個指針從原點出發,那麼他們之後相遇時的位置就是環的入口處。
代碼:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return NULL;
ListNode *one = head->next, *two = one->next;
// check whether there is a cycle in list
while(two != NULL && one != two) {
one = one->next;
two = two->next;
if(two == NULL)
break;
two = two->next;
}
if(two == NULL)
return NULL;
// get the length of cycle - clength
int clength(1);
one = one->next;
while(one != two) {
one = one->next;
++clength;
}
ListNode *p = head;
one = head;
for(int i = 0; i < clength; ++i)
p = p->next;
while(p != one) {
p = p->next;
one = one->next;
}
return p;
}
};
2) 深入分析一下指針在查找環過程中的相遇點:
設鏈表開始處距離環入口處的距離爲k,環的長度爲c。
當慢指針到達入口處時,它走了k步,而快指針此時已經在環內,一共走了2k步,設此時它距離環的入口n步。那麼還需要c-n步,快指針就會和慢指針相遇(快指針每次都趕上慢指針一步)。相遇時的位置就是c-n(慢指針是從環的入口處出發的)。
再考察k與c、n之間的關係。快指針在圈內從起點開始行走了k步到達了n的位置,那麼它們之間的關係滿足:
如果從相遇時的位置開始,讓慢指針再走
實現代碼:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return NULL;
ListNode *one = head->next, *two = one->next;
// check whether there is a cycle in list
while(two != NULL && one != two) {
one = one->next;
two = two->next;
if(two == NULL)
break;
two = two->next;
}
if(two == NULL)
return NULL;
ListNode *p = head;
while(p != one) {
p = p->next;
one = one->next;
}
return p;
}
};