从stackoverflow内外的几个帖子中,我已经知道如何检测链表中的循环,循环的长度。我还找到了如何检测循环开始的方法。
以下是再次参考的步骤。
检测循环:
有两个指针,通常称为野兔和乌龟。将野兔移动2步并将龟移动1.如果它们在某个时刻相遇,那么肯定会有一个循环,并且会合点显然在循环内。
寻找循环的长度:
将一个指针固定在会合点上,同时增加另一个指针直到它们再次相同。随着时间的推移增加一个计数器,满足时的计数器值将是周期的长度。
查找周期的开始
用一个指针开始列表,另一个指向会合点。现在将两者递增,并且满足点是循环的开始。我在纸上使用了一些案例验证了这种方法,但我不明白为什么它应该起作用。
有人可以提供数学证明,说明为什么这种方法有效吗?
答案 0 :(得分:42)
如果您通过指向其第一个节点(列表)
的指针来表示列表
检测循环的算法描述如下:
让我们假设这个算法是正确的。 在此方案中,循环情况由下图表示:
注意除了指向循环开始的节点之外,每个节点都标有其目标数减1的节点。因此,如果一个节点标有 i 并且它不是循环的开头,那么它被标记为 i-1 的节点指向下一个元素。 / p>
上面解释的算法可以被描述为循环,因为其主要步骤(3)是一组子步骤,其重复直到满足退出条件。这迫使我们在算法执行中的迭代次数( t )中表示 pFast 和 pSlow 。
如果列表没有循环,则指针位置将在t的函数中描述为:
然而,有一个循环开始的节点,该函数停止描述指针的演变。假设此指针标有 m ,则该循环包含节点(即和),并将 t = 0 设置为时的迭代值:
如果一个指针确实足以使用所描述的算法检测循环,那么它必须至少存在方程的解决方案。
当且仅当 t 的值有:
时,此等式为真
这以函数结束,该函数生成t的值,这些值是上述等式的有效解决方案:
因此证明了一个慢指针和一个快速指针足以检测链表中的循环条件。
答案 1 :(得分:19)
如果您不使用会面点,您可以使“查找周期开始”证明更简单
让第二个指针不在“会合点”开始,但是M
在第一个指针之前步进。 (其中M
是循环的长度。)
这样,证据非常明显。当第一个指针到达循环的开始时,第二个指针将正好前进M
:也就是在循环开始时。
答案 2 :(得分:8)
slowPointer在meet = x + y
之前行进的距离fastPointer在会面前行进的距离=(x + y + z)+ y = x + 2y + z
由于fastPointer的行进速度是slowPointer的两倍,因此当达到会合点时,两者的时间都是恒定的。
因此,通过使用简单的速度,时间和距离关系2(x + y)= x + 2y + z => x + 2y + z = 2x + 2y => X = Z
因此,通过将slowPointer移动到链接列表的开始,并使slowPointer和fastPointer一次移动一个节点,它们都具有相同的距离。
它们将在链接列表中的循环开始处到达。
答案 3 :(得分:0)
我不认为这是真的,当他们遇到那是起点。但是,如果另一个指针(F)在之前的会合点,那么该指针将位于循环的结尾而不是循环的开始,并且从列表的开头开始的指针(S)将是在循环开始时结束。例如:
开始F作为Fast ans S比他们在9点结束时慢。 现在当我再次开始S时,它将在循环开始时到达,即7但f将在16 ..
如果我错了,请告诉我
答案 4 :(得分:0)
第二部分,声明“找到循环的开始,只需将一个指针移回列表的开头然后迭代它们直到它们相遇”是错误的!
只有当快速指针绕循环完全一次时才是正确的 - 即循环开始之前的部分比循环的长度短 - 但是如果它更长然后算法不起作用;你可能陷入无限循环。
尝试使用包含11个元素的链表,其中第11个指向第7个:
1 1 - > 3 2 - > 5 3 - > 7 4 - > 9 5 - > 11 6 - > 8 7 - > 10 8 - > 7 9 - > 9 9
- 检测到循环
向后移动一个以开始并递增它们: 1 9 - > 2 10 - > 3 11 - > 4 7 - > 5 8 - > 6 9 - > 7 10 - > 8 11 - > 9 7 - > 10 8 - > 11 9 - > 7 10 - > 8 11 - > ...
答案 5 :(得分:-2)
/* Algorithm : P2 is moving through the list twice as fast as P1.
If the list is circular, it will eventually get around P1 and meet */
public boolean hasCycle()
{
DoubleNode p1,p2;
p1=p2=firstNode; //Start with the first loop
try
{
while (p2 != null) //If p2 reaches end of linked list, no cycle exists
{
p1=p1.next; //Move to next
p2=p2.next.next; //Move to 2 steps next
if(p1==p2)
return true; //p1 and p2 met, so this means that there is a cycle
}
}
catch(NullPointerException npe)
{
//This means that p2 could not move forward
return false;
}
return false;
}