链表是否有环是一个经典问题,那么它到底是怎么判断的呢如图
链表环的入口是可以通过数学验证得出:
1:我们假设有两个快慢指针,快指针一下走两个,慢指针一下走一个,那么快指针必定先到环中,在慢指针到入口的时候,快指针已经走了n个环+到了环内某个位置 从这之后 快慢指针都在环中,并且快指针必将在慢指针走一圈之内与慢指针重合,因为快慢指针的相对速度为1,慢指针走1圈,快指针就会相对慢指针走1圈,所以快慢指针必在慢指针走一圈之内重合
2,当慢指针到了入口的地方 我们假设 快慢指针在如下重合,入口到重合位置长度为n,重合位置到入口处为z,环长度为y,从链表开头到入口为x ,y=n+z;
3 以上所述可以导出一个公式
慢指针所走的等于长指针走的
x:链表开头到入口
y:环长度 =(n+z)
n:环入口到重合位置
z:重合位置到入口
m:慢指针到入口时快指针走的环圈数
2(x+n)=x+n+m(n+z)
x+n=m(n+z)
x+n=(m-1)(n+z)
x=(m-1)(n+z)+z
(m-1)(n+z)就是快指针走的圈数减一圈,不影响它们的关系
当(m-1)(n+z)=0时,可以看出x=z
综上可以得知,如果有环的话,快慢必定相遇并且重合位置距离入口的长度等于从链表开头到入口的长度
那么代码就好实现了下面的java的代码
public static ListNode Ring(ListNode root) {
if (root == null) {
return null;
}
ListNode l = root;
ListNode r = root;
while (r != null && r.next != null) { //为啥判断r 是因为r是快指针如果不存在环,快指针直接结束循环
r = r.next.next; //快慢指针迭代
l = l.next;
if (r == l) { //判断重合位置
r = root; //此时快指针回到链表开头
while (true) { //快慢指针速度变为一致开始遍历查找入口
if (r == l)
return r; //返回入口
r = r.next;
l = l.next;
}
}
}
return null; //无环返回null
}