LeetCode OJ :Linked List Cycle II
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?
/**
* 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) {
if((head == NULL) || (head->next == NULL))
return NULL;
ListNode *p, *q;
p = q = head;
p = p->next;
q = q->next->next;
//指针追击问题
while((q != NULL) && (q->next != NULL) && (p != q))
{
p = p->next;
q = q->next->next;
}
if((q == NULL) || (q->next == NULL))
return NULL;
else if(p == q) //链表肯定存在环
{
int flag = 0;
ListNode *r, *first;
r = head;
if((r == p) || (r == q)) //只包含头结点的环
return r;
if(p->next == q->next->next)//只包含尾结点的环
return p;
while((p != r) && (q != r))
{
p = p->next;
q = q->next->next;
while(p != q)
{
if((p == r) || (q == r))
return r;
p = p->next;
q = q->next->next;
}
r = r->next;
if((r == p) || (r == q))
return r;
}
}
}
};
看到一个更牛叉的解法:这实际上是一个经典的龟兔赛跑问题。
假设:
- x:环开始的索引结点
- y:环的长度
- 兔的赛跑速度是龟的两倍
- 这样兔肯定在环内的某一点上追上龟,假设这一点为m
x+ty+m = 2(x+ky+m)
故有:x+m = (t-2k)y。所以(x+m)mod y = 0,所以有如下方法:
让快指针停在两指针相遇的点,然后让慢指针回到头指针的位置,两个指针同时出发,每次走一步。
当慢指针走到环的第一个结点处(即走了x步),此时快指针距离环的第一个结点的位置为:x+m,即也在环的第一个结点处。所以此时两个指针又相遇了。
这样就可以判定环的第一个结点的位置了,即,两指针相遇的位置!
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
ListNode* slow = head;
ListNode* fast = head;
do{
if( !slow || !fast ) return NULL;
slow = slow->next;
fast = fast->next;
if( fast ) fast = fast->next;
else return NULL;
}while( slow != fast );
slow = head;
while( slow != fast ){
slow = slow->next;
fast = fast->next;
}
return slow;
}
};