Algorithm 在链表中查找循环的开始

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 乌龟和兔子相遇后,我们需要在链表中找到循环的起始点,因此两个指针开始,一个来自头部,另一个来自兔子。我的问题是,为什么这个代码块总是有效?为什么不存在这样一

我对leetcode问题(链表循环II)有疑问,其解决方案已列出。具体而言,我想询问解决方案中的以下代码块:

node1, node2 = head, hare
while node1 != node2:
        node1 = node1.next
        node2 = node2.next

return node1

乌龟和兔子相遇后,我们需要在链表中找到循环的起始点,因此两个指针开始,一个来自头部,另一个来自兔子。我的问题是,为什么这个代码块总是有效?为什么不存在这样一种情况,
node2
可能总是落后于
node1

这里有两个步骤。首先,我们从代数上证明了解的含义,然后我们证明了解的存在。这是一个“倒退”的过程,然后又是一个前进的过程——我假设上面的解决方案是正确的,检查其含义是什么,并证明它们是可以发生的

我不确定从下面的证据中是否有一个简单的直觉。就我个人而言,我看不出有什么可以推演的小事

步骤1

将我们的节点表示为
0…L
,循环起点表示为
C
,兔子和乌龟的第一个汇合点表示为
M

引理1
M=(L-C)J
,其中J是某个整数

这是通过观察兔子经过的东西得出的:

  • 总距离仅为
    2M
    ,因为乌龟唤醒了
    M
    节点(在这里,将起点设置为0开始起作用,否则我们需要-1s)
  • 另一方面,兔子到达
    M
    ,然后继续进行
    L-C
    长度循环。如果它困扰您,它可能会在几次运行中“错过”
    M
    ,请记住这并不重要-最终它会到达
    M
    ,您可以通过单步后退,展开整数个周期,然后从
    M
    返回到0
  • 因此:

    我们完成了

    引理2如果
    M
    存在,
    C=(L-M)+(L-C)I
    其中
    I
    是某个整数

    这比较容易。我们再来看看这两个节点必须通过什么。头部必须精确通过
    C
    (LHS),而集合点的节点必须从
    M
    到达
    L
    ,然后再经过一个节点才能到达
    C
    。因为我们是0计数,所以结果是
    L-M
    。现在,它必须通过
    L-C
    一个整数周期,来证明上述内容

    步骤2

    现在我们展示了解决方案的存在

    引理3
    J
    来自引理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的引理4
    I
    存在

    要了解这一点,我们只需要了解
    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