给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
设置快慢指针, 都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点
。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口
。
证明:
设置快慢指针fast和slow,fast每次走两步,slow每次走一步。如果链种有环,两者一定会环内相遇(因为slow一旦进环,可看作 fast 在追赶 slow 的过程,因为快慢的问题,最后 fast 必然追上 slow)。
设链表头到环入口长度为 a,环入口到相遇点长度为 b,相遇点到环入口长度为 c
相遇时:
快指针前进距离 = a+(b+c)n+b;
n>=1 , b+c:环的长度,n:绕环的圈数(n>=1,即最少一圈)。
慢指针前进距离 = a+b;
快指针速度是慢指针的两倍可得:
a+(b+c)n+b = 2x(a+b) ==> a=(n-1)(b+c)+c
即
链表头到入口距离 = (n-1)圈环长度 + 相遇点到入口距离
所以快慢指针分别从链表头和相遇点出发,最后必相遇于环入口。
代码:
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode fast = pHead;
ListNode slow = pHead;
if(pHead == null || pHead.next==null){
return null;
}
while(pHead!=null && pHead.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow) break;
}
fast = pHead;
while(fast!=slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}