BM7题解 | #链表中环的入口结点#
链表中环的入口结点
https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4
双指针解决环的入口
思路来自代码随想录
我们把整个路径分为三段:
第一段:没有环的,x
第二段:环的入口到相遇的地方,y
第三段:相遇的地方到入口,z
定义两个指针:
fast指针:一次走两格
slow指针:一次走一格
两个指针都从head触发,最后一定会在环内相遇,因为fast每次都比slow多走一格
再定义两个指针:
p1从head出发,p2从相遇的地方出发,每个指针一次都走一格,最后会在入口处相遇
请看如下证明:
slow走的节点个数为 x + y
fast走的节点个数为 x + y + n(y + z),因为fast走得快,可能在环内走了n圈才和slow相遇
因为fast一次走两格,slow一次走一格,所以fast走的节点个数是slow的两倍,有:2(x+y) = x + y + n(y + z)
两边都消掉一个 x + y,得到 x + y = ny + nz -> x = (n-1) y + nz --> x = (n-1) y + (n - 1) z + z
为什么最后要拆一个z出来呢?z是从相遇的节点到入口的距离, y + z 正好是环内一圈的距离,这样就有
x = (n - 1) (y + z) + z
x的距离,也就是head到入口的距离正好等于 n - 1 圈的距离 + 相遇的点到入口的距离,那么p1 和 p2就一定会在入口处相遇
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; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if (fast == slow) { // 遍历过程中一旦相遇则说明有环 ListNode p1 = pHead; ListNode p2 = fast; while (p1 != p2) { p1 = p1.next; p2 = p2.next; } return p1; } } return null; } }