考虑以下链接列表:
1->2->3->4->5->6->7->8->9->4->...->9->4.....
以上列表的循环如下:
[4->5->6->7->8->9->4]
在白板上绘制链接列表,我尝试手动解决不同的指针步骤,看看指针是如何移动的 -
(slow_pointer_increment, fast_pointer_increment)
因此,不同情况的指针如下:
(1,2), (2,3), (1,3)
前两对增量 - (1,2)和(2,3)工作正常,但当我使用该对(1,3)时,算法似乎不适用于这对。是否有一个规则,我们需要增加多少步骤让这个算法保持为真?
虽然我搜索了较慢和较快指针的各种增量步骤,但到目前为止我还没有找到一个相关的答案,说明为什么它不适用于此列表中的增量(1,3)。
答案 0 :(得分:1)
如果指针增量和循环长度之间的差异是互质的(即它们的最大公约数必须为1),则只保证算法在任何位置找到一个循环。
对于一般情况,这意味着增量之间的差异必须为1(因为它是唯一与所有其他正整数相互作用的正整数)。
对于(1,3)
,差异为3-1=2
,周期长度为2
,2
和2
不是互质,因此算法不是保证找到循环。
理解这一点的关键是,至少为了检查指针是否满足,慢速和快速指针'周期内的位置仅相互关联。也就是说,这两者可以被认为是等价的:(两者的差异为1)
slow fast slow fast
↓ ↓ ↓ ↓
0→1→2→3→4→5→0 0→1→2→3→4→5→0
因此,我们可以根据slow
保持不变的位置和fast
以fastIncrement-slowIncrement
的增量移动的位置来考虑这一问题,此时问题就变成了:
从任何位置开始,我们能够以某个速度(模式周期长度)到达特定位置吗?
或者,更一般地说:
我们能否以某种速度(模式周期长度)到达每个位置?
只有在速度和周期长度是互质的情况下才会出现这种情况。
例如,查看速度为4和长度为6的循环 - 从0开始,我们访问:
0, 4, 8%6=2, 6%6=0, 4, 2, 0, ...
- GCD(4,6)= 2,我们只能访问每一个元素
要看到这一点,请考虑上面给出的示例的(1,5)(差值= 4)的增量,并看到指针永远不会满足。
我应该注意到,据我所知,(1,2)增量被认为是算法的基本部分。
使用不同的增量(根据上述约束)可能会有效,但这将是一个远离官方"算法并且涉及更多的工作(因为指向链表的指针必须迭代递增,你不能在一个步骤中将它递增超过1),而对于一般情况没有任何明显的优势。
答案 1 :(得分:0)
伯恩哈德·巴克 (Bernhard Barker) 的解释很到位。 我只是在添加它。
为什么指针之间的速度差和循环长度应该是 互质数?
假设指针(例如 v
)和循环长度(例如 L
)之间的速度差异不是互质的。
所以存在一个大于 1 的 GCD(v,L)(比如 G
)。
因此,我们有
v
=指针之间的速度差L
=循环的长度(即循环中的节点数)G
=GCD(v,L)由于我们只考虑相对位置,因此本质上 slow
是静止的,而 fast
以相对速度 v
移动。
让 fast
位于循环中的某个节点。
由于 G
是 L
的除数,我们可以将循环划分为总帐部分。从 fast
所在的位置开始划分。
现在,v
是 G
的倍数(比如 v=nG
)。
每次 fast
指针移动时,它都会跳过 n
部分。所以在每个部分,指针到达一个节点(基本上是一个部分的最后一个节点)。每次fast
指针都会落在每个部分的结束节点。参考下图
正如上面伯恩哈德所说,我们需要回答的问题是 我们可以到达以某种速度移动的每个位置吗?
如果我们有现有的 GCD,答案是否。正如我们所见,fast
指针只会覆盖每一部分的最后一个节点。