142. Linked List Cycle II

这题本来以为很简单,看了题解发现各种推倒,被吓到了。。
找了一个简单的容易懂的题解:

142. Linked List Cycle II_第1张图片
cycle2.jpg

以下讲解引用自: http://www.jianshu.com/p/ce7f035daf74

图中,
X是链表的起点。
Y是环的起点。
Z是fast和slow首次相遇的地方(二者同时从X出发,slow每次移动一步,fast每次移动两步)。
a, b, c分别表示XY(蓝色), YZ(红色), ZY(绿色)的长度。
当fast和slow在Z点首次相遇时:
fast移动的距离是:a + b + c + b
slow移动的距离是:a + b
因为fast的移动速度是slow的两倍,所以:
(a + b + c + b) == 2 * (a + b)
由此可以推出:
a == c
我们需要用上面的推论来寻找环的起点(Y)。
当fast和slow首次相遇时,我们就到了Z点。
由于a == c,也就是X到Y 与 Z到Y的距离相等。
因此,如果我们让指针p和q分别从X和Z出发,并且每次都移动一步,当它们相遇时,恰好就是环的起点Y。

我说这个推倒简单,是因为这个推导有一个问题,就是有可能runner并不是只在一圈内就遇到了walker。但是无伤大雅,无论经过几圈相遇,a=c仍然是可行的,所以这种相遇后分别走一步直到相遇的方法是可行的。就不要考虑太复杂的数学推导啦。

下面是我按上面思路写的Java代码:

    public ListNode detectCycle(ListNode head) {
        if (head == null) return null;
        ListNode walker = head;
        ListNode runner = head;
        ListNode meetPoint = null;
        while (runner.next != null && runner.next.next != null) {
            walker = walker.next;
            runner = runner.next.next;
            if (walker == runner) {
                meetPoint = walker;
                break;
            }
        }
        if (meetPoint == null) return null;
//注意这里的while条件
        while (head != meetPoint) {
            head = head.next;
            meetPoint = meetPoint.next;
        }
        return head;
    }

迅速写出后提交两次AC,感觉挺舒服的。

你可能感兴趣的:(142. Linked List Cycle II)