问题描述:
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?
分析:这个题比上个题稍微复杂一点,这里要分为三步:第一步,判断是否有环,第二,如果有环,找到环的长度。第三,使用快慢指针,间距分别为环的长度,同时运动,当两者相等时,该点为环的起始点。
代码如下:4ms
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
if(!head)
return NULL;
struct ListNode *slow = head,*fast = head->next;
while(slow && fast){
if(slow==fast)
break;
slow = slow->next;
fast = fast->next;
if(!fast)
break;
fast = fast->next;
}
if(slow!=fast)
return NULL;
//check the length of circle
fast = slow->next;
int length = 1;
while(fast!=slow){
length++;
fast = fast->next;
}
slow = head;
fast = head;
while(length--){
fast = fast->next;
}
while(slow!=fast){
slow = slow->next;
fast = fast->next;
}
return slow;
}
在网上看到了很巧妙的一种方法:思路是这样的,因为快指针每次运动2,慢指针每次运动1,所以当出现环时,快慢指针一定会相遇,在相遇的位置时,快指针运动了2m,慢指针运动了m,那么2m-m=m就是环长度的整倍数。
假设此时,一个指针从头开始出发,一直运动m,那么还是会运动到相遇点,而另一个指针从当前位置出发,经过m,同样会运动到相遇点。当然,此时二者的运动速度都是1,那么当两个指针都进入环之后将会保持一致相对静止,所以除非在进入环的一刻二者就保持相等。否则我们上面的结论是不可能出现的。
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
if(!head)
return NULL;
struct ListNode *s = head,*f = head;
while(f){
if(f) f = f->next;
if(f) f = f->next;
if(s) s = s->next;
if(s == f)
break;
}
if(!f)
return NULL;
s = head;
while(f!=s){
f = f->next;
s = s->next;
}
return s;
}