这题本来以为很简单,看了题解发现各种推倒,被吓到了。。
找了一个简单的容易懂的题解:
以下讲解引用自: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;
}