题目
分析
用multimap的键存已遍历过的结点指针,当某个键存入的次数不为0时,说明已经进入循环,此时的结点为循环的起始结点。
题解
/**
* 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) {
multimap<ListNode *,int>mmap;
if(head == NULL)
return head;
ListNode *p = head;
while(p != NULL){
if(mmap.count(p) != 0){
return p;
}
else{
mmap.insert(pair<ListNode *, int>(p,0));
p = p->next;
}
}
return NULL;
}
};
如果不用多余的空间,则只使用两个指针也可以实现。
一个指针一次走2步,另一个指针一次走1步,若存在循环第二个指针一定会追上第一个指针。
假设存在循环,进入循环之前的距离为a,循环的结点数为b,在距离刚进入点c的地方两个指针相遇。
若一共走了x步,慢指针一共前进了 a+m*b+c,快指针一共前进了a+n*b+c
2*x = a+n*b+c
x = a+m*b+c => 2*x = 2*a +2m*b+2c
=> a+c = (n-2m)*b
此时快指针在c点 若再前进a步 刚好到初始的循环点。
于是可以将慢指针放在起始点,两个指针一次各走一步,当两指针再次相遇时,相遇点为循环的起始点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if (slow == fast){
slow = head;
while (slow != fast){
slow = slow->next;
fast = fast->next;
}
return slow;
}
}
return nullptr;
}
};