解题思路
分为两个阶段思考
- 判断是否有环
- 如果有环,得出环的入口节点
第一阶段参考141 环形链表篇。
主要是第二阶段如何得出环的入口节点。 首先先说方法,额外初始化两个指针ptr1
指向链表头,ptr2
指向相遇点。之后两个指针都已步长为1的速度前进,当两者相遇时,这个节点就是环的入口节点。
为什么两个指针,一个指向链表头,一个指向相遇点,已同样步长前进,最后会在环的入口节点相遇?
- node f 表示链表头
- h点表示相遇点
- node 0表示入口节点
- F表示链表头到环节点的距离
- a表示环节点到相遇点的距离
- b表示相遇点到环节点的距离
从阶段一可知(说明下列式子表达的是环的长度比F要小的情况。这种情况更加通用)
- 2(F+a) = F+n(a+b)+a
- 其中n表示快指针移动的圈数
- 最后可以得出式子 F = na+nb-a
- 从这个式子其实看不出什么结论来,我们来转换一下
- 变成 F = (n-1)(a+b)+b。大家可以反推看看,两者是相同的。
- 有了这个式子,那就可以验证之前的那个结论了。最简单的有当n=1时,F=b。
实现代码
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getInstance(ListNode head){
ListNode slow=head,fast = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(slow == fast){
return slow;
}
}
return null;
}
public ListNode detectCycle(ListNode head) {
ListNode node = getInstance(head);
if(node == null){
return null;
}
ListNode ptr1 = head;
ListNode ptr2 = node;
while(ptr1 != ptr2){
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
return ptr1;
}
}