题目描述:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 为了表示给定链表中的环,我们使用整数 pos来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 说明:不允许修改给定的链表
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点
示例 2:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环
/**
* 思路:设从开始到入环点的距离为 x,从入环点到相遇点的距离为 y,整个环的周长为 c。
* 有两个指针同时从起点走,一个为 s,一个为 f,则相遇时,
* s 走的距离:
* s = x + y + n1 * c(n1 为正整数)
* f 走的距离:
* f = x + y + n2 * c(n2 为正整数)
* 则有:
* f - s = (n2 - n1) * c
*
* 现在我们假设:
* s 的速度为 1,f 的速度为 2,n = n2 - n1
* 由 f - s = (n2 - n1) * c ===> f - s = nc
* 我们知道,两个指针的走的路程、速度不同,但都是从头开始,走到相遇点,时间相同
* 已知 s 的速度为 1 ===> 时间为 s
* 则此时 f = 2s(f 速度是 2,时间是 s)
* 由之前推出的 f - s = nc ===> s + nc = f = 2s ===> s = nc(s 走了 nc 距离)
*
* 我们知道,要到入环点,从开始走 x 距离可以,从开始走 x + nc 距离也可以
*
* 所以,要找到入环点,只需要另外一个指针走 x 距离,而相遇的时候 s 已经走了 nc,
* 所以 s 再走 x 距离,就会和另外一个指针相遇,此相遇点就是入环点
*
* 注意:理论上,也可以让 f 走 x 距离,但是我们知道 s 的速度是 1,相对来说比 f 更容易些
* 所以我们选用 s
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
//用 do...while 因为最开始 fast == slow,必须让 fast 先走两步,slow 再开始走
do{
if(fast==null){
return null;
}
if(fast.next==null){
return null;
}
fast = fast.next.next;
slow = slow.next;
}while(fast!=slow);
//fast 和 slow 相遇
ListNode p = head;
while(p!=slow){
p = p.next;
slow = slow.next;
}
return p;//return slow; 也可以
}
}