zoukankan      html  css  js  c++  java
  • 142. Linked List Cycle II

    这道题我原来是不会的,然后自己思考了一下,发现其实是个数学问题,虽然方法用的是双指针,但是我还是从数学层面进行解释吧。

    这道题是在141. Linked List Cycle基础上的变形题,那道题就是用双指针法,一个快指针fast每次走两步,一个慢指针slow每次走一步,如果快指针能和慢指针相遇,则说明存在环。

    我们首先看一下有环的情况,例如下面这个链表

    这个右边我是故意画成这种环状的,看着比较清晰,其实和原题的链表是一样的。

    首先我们必须清楚一点,如果存在环,快指针和慢指针一定是在环中的某个结点位置相遇的,不可能在环之外的结点处相遇。

    我们假设环开始的结点下标为i(下标从0开始),对于上图,i=2。
    同时,我们设整个链表长度为len,对于上图,len=8。

    那么我们很容易知道,环的长度为len-i,我们记环的长度为circle,即circle = len-i。

    现在我们假设,当快指针和慢指针相遇的时候,慢指针一共走了n步。现在问题是,走了n步的慢指针,它现在所处结点的下标是多少?

    不难算出,走了n步之后,下标为:

    Xslow = i+(n-i)%circle

    前提当然是n≥i,因为我们刚才说了,快慢指针相遇一定是在环内,所以n≥i必然成立。

    慢指针走了n步,快指针则走了2n步,因为快指针速度是慢指针的2倍。

    同理,走了2n步的快指针,它所在结点的下标为:

    Xfast = i+(2n-i)%circle

    现在两者相遇了,意思就是说 Xslow = Xfast

    于是有:i+(n-i)%circle = i+(2n-i)%circle,即 (n-i)%circle = (2n-i)%circle。

    这就是一个简单的同余方程,有无数个解,解为:
    (2n-i) = (n-i) + k*circle, k=1,2,3...

    但是注意,我们所说的相遇是第一次相遇,那么这个解就唯一了,即:
    (2n-i) = (n-i) + circle

    即,n = circle

    没想到吧,结论竟是如此的简单!

    不信,你看看上面那幅图,图中circle=6(即圈中结点的个数),那么快指针和慢指针第一次相遇时,慢指针一定是走了6步,此时慢指针到了下标为6的位置。

    事实上快指针走了2*6=12步,刚好也到下标为6的结点上面了。

    现在问题是,我在得到了这个相遇的结点的下标后,我怎么找到环中第一个结点呢?也就是下标为i的结点。

    我们不要忘了,第一次相遇,快指针是比慢指针刚好多走了一圈,有人说你怎么知道是刚好多走一圈,因为刚才那个同余方程的解我们是令k=1得到的,k=1就是说多走了一圈。

    假设从相遇结点到下标为i的结点需要y步,那么从小标为i结点到相遇结点自然要走circle-y步,于是
    2n = i+circle+circle-y
    n = i+circle-y

    我们消掉其中的n,就会得到
    i = y

    i=y说明了什么?

    说明了在找到相遇位置后,让一个指针从整个链表的头部出发,另外一个指针从相遇位置出发,两个指针每次走一步,当他们相遇的时候,就正好到了i号结点位置,i号结点,就是题目要求我们求的结点。

    由于这里我们下标是从0开始编号的,所以head到i号结点的距离(所需要走的步数)也正好是i。

    于是我们可以给出如下代码:

    class Solution {
    public:
        ListNode *detectCycle(ListNode *head) {
            ListNode *slow = head, *fast = head;
            while (fast && fast->next) {
                slow = slow->next;
                fast = fast->next->next;
                if (slow == fast) break;
            }
            if (!fast || !fast->next) return NULL;
            slow = head;
            while (slow != fast) {
                slow = slow->next;
                fast = fast->next;
            }
            return fast;
        }
    };
    
    只有0和1的世界是简单的
  • 相关阅读:
    LAB02:Selenium的安装与使用
    HW03:Exercise Section 2.3
    LAB01:安装 Junit(4.12), Hamcrest(1.3) 以及 Eclemma并完成一次三角形问题的测试
    HW02:根据程序回答问题
    HW01:程序中的错误
    Postman 接口测试
    Python3.7、Eclipse 4.5、 Java 8、 PyDev 5.2.0、 selenium-3.14.0环境搭建
    Java + selenium 实现web自动化简单示例
    java Junit自动化测试框架环境搭建
    java TestNg自动化测试框架环境搭建
  • 原文地址:https://www.cnblogs.com/nullxjx/p/14248739.html
Copyright © 2011-2022 走看看