解法一:
使用HashSet存储每个节点:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode node = head;
HashSet<ListNode> set = new HashSet<ListNode>();
while (node != null) {
if (set.contains(node)) {
return node;
} else {
set.add(node);
}
node = node.next;
}
return null;
}
}
解法二
使用快慢指针:
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null)
return null;
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast) { //标记
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
}
标记处思路解析
假设slow
和fast
相遇时,slow
总共走了k步,那么fast
走了2k步,假设圆环长度为h,则k = m + ah + n
,2k = m + bh + n
,相减得k = (b - a)h
,也就是说,k是h的整数倍。
如上图所示,假设slow
和fast
的相遇点为o
,这时假设起点和环起点的距离为m
,环起点和相遇点的距离为n
,令slow
回到起点,fast
在相遇点,两者以相同步幅出发,走了m
的步,将会在环起点相遇,证明过程如下:
若 slow 与 fast 相交于环起点,则说明它们走过的长度都是 m,假设 fast 在环中走过的长度为 ch - n,
那么就有 m = ch - n。
上文讲到过 k = m + ah + n,那么 m = k - ah - n,又因为 2k - k = k = (b - a)h,
代入得 (b - 2a)h - n = m,这里的 b - 2a 与 c 都是整数,它们的大小关系不用深究,因为 fast 是一
直在环里绕圈,最终会和 slow 相交于环起点。