Algorithm 在链表中查找循环的开始
我对leetcode问题(链表循环II)有疑问,其解决方案已列出。具体而言,我想询问解决方案中的以下代码块:Algorithm 在链表中查找循环的开始,algorithm,data-structures,linked-list,Algorithm,Data Structures,Linked List,我对leetcode问题(链表循环II)有疑问,其解决方案已列出。具体而言,我想询问解决方案中的以下代码块: node1, node2 = head, hare while node1 != node2: node1 = node1.next node2 = node2.next return node1 乌龟和兔子相遇后,我们需要在链表中找到循环的起始点,因此两个指针开始,一个来自头部,另一个来自兔子。我的问题是,为什么这个代码块总是有效?为什么不存在这样一
node1, node2 = head, hare
while node1 != node2:
node1 = node1.next
node2 = node2.next
return node1
乌龟和兔子相遇后,我们需要在链表中找到循环的起始点,因此两个指针开始,一个来自头部,另一个来自兔子。我的问题是,为什么这个代码块总是有效?为什么不存在这样一种情况,
node2
可能总是落后于node1
?这里有两个步骤。首先,我们从代数上证明了解的含义,然后我们证明了解的存在。这是一个“倒退”的过程,然后又是一个前进的过程——我假设上面的解决方案是正确的,检查其含义是什么,并证明它们是可以发生的
我不确定从下面的证据中是否有一个简单的直觉。就我个人而言,我看不出有什么可以推演的小事
步骤1
将我们的节点表示为0…L
,循环起点表示为C
,兔子和乌龟的第一个汇合点表示为M
引理1M=(L-C)J
,其中J是某个整数
这是通过观察兔子经过的东西得出的:
2M
,因为乌龟唤醒了M
节点(在这里,将起点设置为0开始起作用,否则我们需要-1s)M
,然后继续进行L-C
长度循环。如果它困扰您,它可能会在几次运行中“错过”M
,请记住这并不重要-最终它会到达M
,您可以通过单步后退,展开整数个周期,然后从M
返回到0M
存在,C=(L-M)+(L-C)I
其中I
是某个整数
这比较容易。我们再来看看这两个节点必须通过什么。头部必须精确通过C
(LHS),而集合点的节点必须从M
到达L
,然后再经过一个节点才能到达C
。因为我们是0计数,所以结果是L-M
。现在,它必须通过L-C
一个整数周期,来证明上述内容
步骤2
现在我们展示了解决方案的存在
引理3J
来自引理1。存在的情况是L>=M>=C
如果存在一个J
,这样(L-C)J=C
我们就完成了。否则,取最小的K
,使
(L-C)K > C
通过否定假设
(L-C)K > L => (L-C)K - (L-C) > L - (L-C) => (L-C)(K-1) > C
与假设相矛盾的K
最小。因此,J=K
解决了我们的问题
引理2的引理4I
存在
要了解这一点,我们只需要了解C=(L-M)I
是否有解,其中I
和J
是整数和正的。我们将M
替换为:
C = (L-M) + (L-C)I = L-(L-C)J+(L-C)I = (1-J+I)L + (J-I)C => (1-J+I)L=(1-J+I)C
因此,如果有一个整数解,要么是无趣的L=C
,要么是
I=J-1
Q.E.D
I=J-1