据我所知,为了检测链表中的循环,我可以使用Hare和Tortoise方法,该方法包含2个指针(慢速和快速指针)。但是,在阅读了wiki和其他资源之后,我不明白为什么这两个指针会在O(n)时间复杂度上得到满足。
答案 0 :(得分:30)
这是一次非正式证明的尝试。
周期的形状无关紧要。它可以有一个长尾巴,一个朝向末端的循环,或者只是一个从开始到结束而没有尾巴的循环。无论循环的形状如何,有一件事是清楚的 - 乌龟指针无法赶上野兔指针。如果两人永远相遇,野兔指针必须从后面赶上乌龟指针。
有了这个,考虑两个可能性:
所有更远的距离最终会减少到一两个。
假设乌龟指针始终先移动(也可能是另一种方式),那么在第一种情况下,乌龟指针向前迈出一步。现在它们之间的距离是2.当野兔指针现在采取两步时,它们将落在同一节点上。这是为了便于理解而说明的相同内容。太多的文字可能会妨碍你。
♛ = hare ♙ = tortoise X = both meet ..♛♙... #1 - Initially, the hare is one step behind the tortoise. ..♛.♙.. #2 - Now the tortoise takes one step. now hare is two steps behind. ....X.. #3 - Next, the hare takes two steps and they meet!
现在让我们考虑第二种情况,它们之间的距离是2.慢速指针向前移动一步,它们之间的距离变为3.接下来,快速指针向前移动两步,它们之间的距离减小到1与我们已经证明他们将再一次见面的第一个案例相同。再次,说明以便于理解。
.♛.♙... #1 - Initially, the hare is two steps behind the tortoise. .♛..♙.. #2 - Now the tortoise takes one step and they become three steps apart. ...♛♙.. #3 - Next, the hare takes two steps which is identical to previous case.
现在,至于为什么这个算法保证在O(n)中,使用我们已经确定的野兔将在它前进之前遇到乌龟。这意味着一旦两者都在环路内,在乌龟完成另一轮之前,它将满足野兔,因为野兔的移动速度是原来的两倍。在最坏的情况下,循环将是一个具有n个节点的圆。虽然乌龟只能在n个步骤中完成一轮,但野兔在那段时间内可以完成两轮。即使野兔在第一轮中错过了乌龟(它将会),它肯定会在第二轮中赶上乌龟。
答案 1 :(得分:3)
让迭代器A
和B
分别按1和2进行列表。 Consdier存在一个循环。然后,当A
进入循环时,B
已经位于其中的某个位置。如果循环的长度为K
,那么B
将在]K/2[
次移动中围绕它运行,因此最多在2*]K/2[
次迭代中我们会遇到{{1}的情况} B
位于A
或1: B->A
的{{1}}后方,并且2: B->.->A
转过来。在此之后,很明显,他们将在B
或1
次移动中相遇。因此,如果循环存在并从某个位置2
开始,那么我们最多只进行P
次迭代。
答案 2 :(得分:-1)
//if you just want to check if there is a loop
loop = false;
item = head-of-list;
while (item != nil)
{
if (item.next < 0)
{
loop = true;
break;
}
else
{
actual = item;
item = item.next;
actual.next = actual.next * -1;
}
}
return loop;