Given a linked list, determine if it has a cycle in it.
Follow up: Can you solve it without using extra space?
这道题想做出来不难,关键是快慢指针这种一般想不到。。
一般想到的是拿哈希存储已经经过的pointer
这种空间复杂度O(n)
快慢指针这个很巧妙,设置两个指针fast和slow,fast一次走两步,slow一次走一步,这样二者如果能够相遇,那么表示有环
class Solution {
public:
bool hasCycle(ListNode *head) {
//这种想法是错误的,因为有可能在中间的地方出现换,那就gg了
// //有环应当能遍历到自己
// ListNode* temp=head;
// while(temp!=NULL){
// temp=temp->next;
// if(temp==head) return true;
// }
// //于是想到记录每一个出现过的pointer
// unordered_map<ListNode*,bool> visited;
// ListNode* temp=head;
// while(temp!=NULL){
// //首先判断它是否在map里
// if(visited.find(temp)!=visited.end()){
// return true;
// }
// else{
// visited[temp]=true;
// temp=temp->next;
// }
// }
//上面的办法时间复杂度O(n^2) 空间复杂度O(n)
ListNode* slow=head,*fast=head;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast) return true;
}
return false;
}
};
Linked List Cycle II所将的是要我们找出这个入口点
当fast与slow相遇时,slow肯定没有遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,fast走了2s步,设环长为r,则
2s=s+nr
s=nr
设整个链表长L,环入口点与相遇点距离为a,起点到环入口点的距离为x,则
x+a=nr=(n-1)r+L-x
x=(n-1)r+(L-x-a)
L-x-a为相遇点到环入口点的距离
由此可知,从相遇点出发和从起点出发的两个指针,它们一定会在入口的地方相遇
和这篇文章考虑的类似
http://blog.sina.com.cn/s/blog_6f611c300101fs1l.html
不过他没有考虑nr的情况,所以显得有点不严谨,不过做法是完全一样的。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//我忽略了一个严重的问题,就是在二者相遇之前,fast有可能已经在环内走了n圈了....
// ListNode* slow=head,*fast=head;
// int fast_count=0;
// while(fast && fast->next){
// slow=slow->next;
// fast=fast->next->next;
// fast_count+=2;
// if(slow==fast) break;
// }
// if(fast==NULL || fast->next==NULL) return NULL;
// //直到这里,fast_count和slow_count分别记录的走的步数
// //让fast停下,slow继续走
// int circle_count=0;
// do{
// slow=slow->next;
// circle_count++;
// }while(slow!=fast);
// //一开始fast_count比slow_count多走了一圈,然后除去这个周长
// //就是不在环里的部分
// int k=fast_count-circle_count;
// slow=head;
// for(int i=1;i<k;i++,slow=slow->next);
ListNode* slow=head,*fast=head;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
//另一节点从起点开始出发
ListNode* slow2=head;
while(slow!=slow2){
slow=slow->next;
slow2=slow2->next;
}
//二者会在入口相遇
return slow2;
}
}
return NULL;
}
};