原题链接:Linked List Cycle II
如果没有follow up 这道题会非常简单,也非常容易想到,代码如下:
/**
* 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) {
/*
遍历链表,辅助set,如果遍历到的节点存在set中,说明循环开始了,返回,否则将节点插入到set中。否则直至遍历完,返回NULL;
Time Complexity:O(N)
Space Complexity:O(N)
*/
if(!head || !head->next)return NULL;
set<ListNode*>liset;
while(head){
if(liset.find(head)!=liset.end())return head;
else{
liset.insert(head);
head=head->next;
}
}
return NULL;
}
};
但是有了follow up的限制之后,不允许使用额外的空间,就需要点技巧了。有这么个方法:使用快慢指针,当快慢指针第一次相遇之后,将慢指针移动回头结点,然后以慢指针的速度移动快慢指针,再次相遇就是环初始节点。证明其实也很简单,可以参考(出处)
明白了思路,代码就很简单了,如下
/**
* 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) {
/*
使用快慢指针,如果存在环,当快慢指针第一次相遇,将慢指针移回头结点,在以同样的速度移动快慢指针,再次相遇即是环初始节点
Time Complexity:O(2a+b) (a:头结点到环初始节点距离,b:环初始节点到相遇节点的距离)
*/
if(!head || !head->next)return NULL;
ListNode* slow=head->next,*fast=head->next->next;
while(fast && fast->next){
if(fast==slow){
slow=head;
while(true){
if(slow==fast)return slow;
slow=slow->next;
fast=fast->next;
}
}
slow=slow->next;
fast=fast->next->next;
}
return NULL;
}
};