难点在于不使用额外空间
解法思路如下:(参考https://discuss.leetcode.com/topic/58134/o-n-time-and-o-1-space-java-solution-with-chinese-explanation)
步骤一:通过Linked List Cycle的方式,则快慢指针(快指针一次两步,慢指针一次一步)相遇时,则表示存在环,且相遇点在环上。
步骤二:如果环存在,记:
c表示从head到环起始点的距离;
s表示从环起始点到快慢指针相遇点的距离;
cycle表示环的长度;
distance(pointer)表示指针走过的距离;
性质:
a)快指针走过的距离是慢指针走过距离的二倍
b)快指针和慢指针会相遇,是因为快指针已经套了慢指针一圈(且套第一圈时就会相遇,因为快指针快追上慢指针时,相距要么为1要么为2,为1时,下一次移动后相遇,为2时,在经过两次移动相遇)
于是有:
distance(slow)=c+s, distance(fast)=2(c+s)
性质a和b -> distance(fast)-distanc(slow)=k * cycle=2(c+s) - (c+s) = c+s; k = 1 or 2
-> c = k * cycle - s (k = 1 or 2)
又由于:环长度为cycle,两指针距离环起点距离为s,在走k*cycle-s则重新到达起点;且c为从head到环起点的距离,所以从head经过距离c会到达环起点,又c=k*cycle - s;所以用两个指针,同时从快慢指针的相遇点和head出发,每次移动距离为1,经过k*cycle - s(不论k==1还是k==2)会在环起点相遇。
代码如下 :
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if (slow == fast){
slow = head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
}