【外企面试】求一个链表中环的入口【强势证明】
此题没有代码,是一道面试题。题目很好理解,有个链表,先判断是否有环,如果有环则求出环的入口。
这道题跟好几位offer收割机讨论过,基本都是已知leetcode或哪里的方法,证明该方法的正确性。
我和我家阳哥,试图证明,策略是可以推导出来的。证明如下:
首先,要判断一个链表是否有环,机智的做法是快慢指针,令快指针fast每次走两步,慢指针slow每次走一步,那么fast如果能和slow相遇,就证明,链表中有环。
那么有环之后,如何寻找环的入口呢?
(1)首先,我们定义几个变量:
- ListHead表示链表头
- RingEntry表示环入口指针
- x表示ListHead与RingEntry之间的距离(两个相邻节点间的距离为1)
- pos表示slow第一次走到RingEntry时,fast所在位置与RingEntry之间的距离,假设入环后顺时针走
- y表示slow与fast的相遇点与RingEntry之间的距离
- r表示环的长度(环中节点个数-1)
(2)其次,我们需要证明一个结论---slow入环后,一圈之内必定与fast相遇
这个结论其实很好证明,我们用反证法。假设slow走了一圈又回到了RingEntry,这一过程中,都没与fast相遇。当slow回到RingEntry时,fast必定在距RingEntry为pos的位置。这一状态与slow刚入环时的状态一样,在这一圈中slow与fast都没有相遇,那么之后只会不断重复之前的路径,永不会相遇。
因为我们坚信 有环的话,slow和fast必相遇的,因而上述假设不成立,slow入环后,一圈之内必定与fast相遇。
(3)有了(2)的结论,就可以得出下列等式:
- slow首次到达RingEntry时,走了x步,此时fast应该走了2x的距离。又fast位于距离RingEntry为pos,那么:
2x = x + k * r + pos(k表示fast在环中已经绕的圈数) ------> pos = x - k * r
- slow可以看做是比fast快了 r - pos步,又slow与fast相遇时,slow走了y步,因而有:
2y - y = r - pos ------> y = r - pos
- 从相遇点开始,slow至少再向前 r - y 步就可以到达环入口了,那么
r - y = r - r + pos = pos = x - k * r ------> r - y + k * r = x
之所以要把k * r移到 等号 的左边,是因为 k * r 代表着绕着环 k 圈,到达的位置还是 r - y步后到达的位置。
根据最后一个等式,我们就可以看出,slow再向前走 x 步 一定会到RingEntry。
所以寻找环入口的方式为:相遇点后,slow 从相遇点开始,tmp从 ListHead 开始,同时每次走一步,两个相遇点就是RingEntry!