题目
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
方法一
思路
依次遍历所有节点,当一个节点的下一个节点是之前出现过的节点,说明此时形成了环,且此时的“下一个节点”即环的第一个节点。
代码
/**
* 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) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
ListNode *p=head;
while(p)
{
for(ListNode *q=head; q!=p; q=q->next)
if(q==p->next)
return q;
if(p==p->next)
return p;
p=p->next;
}
return NULL;
}
};
方法二
思路
让我们先来想想,如果甲乙两个人处在一个环形跑道上(间隔以步为单位)的任意两点,不妨设两人距离相差 N 步,两人朝同一方向,甲的速度是1步/次,乙的速度是2步/次,每当甲向前1步(此时乙向前2步),甲乙之间的距离就缩小1步,当甲刚好走了 N 步时,甲乙相遇。
所以,甲乙处在环形跑道上任意两点,当甲以1步/次速度前进,乙以2步/次的速度前进,他们最终会走到同一点。这样容易得到,下图中,当甲乙分别以1步/次,2步/次从A点出发,向环前进的时候,他两最终也会在环上的某点相遇。
现在,我们不妨设A是出发点,B是环开始的点,C是甲乙相遇的点,x为A、B之间的距离,k为B、C之间的距离,n为环的周长。
我们假设甲乙相遇时甲走的路径长度为L,则乙走过的路径长度为 2L,且:
L = x + k + a * n ----(1)
2L = x + k + b * n ----(2)
其中a,b为大于等于0的正整数。两式相减:
L = (b - a)* n ----(3)
由方程(1)(3)可以得出 x + k 是 n 的整数倍。那么甲乙分别在A,C两点,以同样的1步/次的速度前进,两人最终会在B点相遇,即环的起点相遇。(此句要仔细琢磨)
通过上面的知识,现在我们可以这样设计算法,先让甲乙分别以1步/次,2步/次从A点出发,向环前进,当两人相遇时,让乙回到A点,重新以1步/次速度前进,而甲继续从相遇的点以1步/次速度前进,两人最终相遇的点即为环的起点。
代码
/**
* 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)
{
return NULL;
}
ListNode *p = head; //慢指针
ListNode *q = head; //快指针
do
{
if (p->next != NULL)
{
p = p->next;
}
else
{
return NULL;
}
if (q->next != NULL && q->next->next != NULL)
{
q = q->next->next;
}
else
{
return NULL;
}
}while(p != q);
q = head;
while (p != q)
{
p = p->next;
q = q->next;
}
return p;
}
};
总结
方法一的时间复杂度为O(n^2),方法二的时间复杂度为O(n)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。