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?
思路
其实还有更简单的方法,在《Cracking the Coding Interview》上有提到。通过数学计算可以推导出来,用快行指针的方法判断出环后,可以不用计算环大小,把快指针变慢然后放到链头上,两个指针继续走到相碰就剩入口了。
分为三步:判断环,计算环的大小,找到入口
判断环就是老一套,用2倍速指针就行,这个之前的题目里头有;
计算环的大小k,环的大小么,刚才相碰的地方找个指针绕圈圈走。记个数,再碰到相遇地点就是环大小了;
找到入口后,我们有两个普通速度的指针pA,pB,让其中一个pA先往前走k步,然后两个一起开始挪动,可以知道,如果pA与pB又相遇了,那相遇点就是环的入口了。此时pA比pB刚好多走了一整圈。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* meetingNode(ListNode* head){
//Find the meeting node
if(head == NULL)
return NULL;
ListNode* slow = head->next;
if(slow == NULL)
return NULL;
ListNode* fast = slow->next;
while(fast != NULL && slow != NULL){
if (slow == fast)
return slow;
slow = slow->next;
fast = fast->next;
if(fast != NULL)
fast = fast->next;
}
return NULL;
}
ListNode *detectCycle(ListNode *head) {
ListNode* meet = meetingNode(head);
if(meet == NULL)
return NULL;
//Get loop size
ListNode* temp = meet->next;
int count = 1;
while(temp != meet){
count++;
temp = temp->next;
}
//Pick one pointer at start, move `count` steps forward
temp = head;
meet = head;
while(count > 0){
count--;
meet = meet->next;
}
//Find the cycle start
while(temp != meet){
temp = temp->next;
meet = meet->next;
}
return meet;
}
};