【问题标题】:Finding start of cycle in linked list在链表中查找循环的开始
【发布时间】:2020-10-15 11:27:59
【问题描述】:

我对 leetcode 问题(Linked List Cycle II)有疑问,其解决方案列于here。具体我想问一下解决方案中的以下代码块:

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

return node1

乌龟和兔子相遇后,我们需要在链表中找到循环从哪里开始,所以启动了两个指针,一个从头部开始,另一个从兔子开始。我的问题是为什么这个代码块总是有效?为什么不会出现node2 可能最终总是落后node1 一步的情况?

【问题讨论】:

    标签: algorithm data-structures linked-list


    【解决方案1】:

    这里有两个步骤。首先我们展示解决方案在代数上意味着什么,然后我们展示解决方案存在。这是向后“前进”然后再次向前 - 我假设上面的解决方案是正确的,检查有什么含义,并证明它们可以发生。

    我不确定从下面的证明中是否有一个简单的直觉。对于一个人来说,我看不到可以推断出来的东西。

    第 1 步

    表示我们的节点0...L,循环起点为C,兔子和乌龟的第一个交汇点(我们可以只说乌龟吗?),如果存在,则为M

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

    这来自于观察兔子经过的东西:

    1. 总距离仅为2M,因为乌龟唤醒了M 节点(这是将起点设置为0 开始得到回报的地方,否则我们将需要处处-1)。
    2. 另一方面,兔子到达M,然后继续经历L-C长度循环。如果它困扰你,它可能会在几次运行中“错过”M,记住这没关系 - 最后它会到达M,你可以单步倒退,展开整数数量的循环,然后从 M 回到 0。

    所以:

    2M = M+(L-C)J   =>   M = (L-C)J
    

    我们完成了。

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

    这更容易。我们再次看看两个节点必须通过什么。头部必须精确地通过C (LHS),而交汇点的节点必须从M 到达L,然后再经过一个节点才能到达C。由于我们计数为 0,因此最终结果为 L-M。现在它必须经过L-C 整数个循环,证明上述。

    第 2 步

    现在我们证明解决方案存在。

    引理 3 来自引理 1 的 J。存在使得 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 解决了我们的问题。

    引理 4 来自引理 2 的 I 存在。

    要看到这一点,我们只需要看看C = (L-M)I 是否有解决方案,其中IJ 是整数和正数。我们替换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

    【讨论】:

      猜你喜欢
      • 2015-08-01
      • 2012-07-20
      • 2011-02-25
      • 1970-01-01
      • 2021-10-16
      • 2011-12-15
      • 2012-05-03
      相关资源
      最近更新 更多