如何判断链表有环,这个问题很简单,有环的链表,在遍历的时候会永远在环里转下去。
但如何返回入环的第一个节点,当然最简单的思路是用额外的空间记录是否访问过该节点,如果访问过,就立刻停止遍历,并返回。
在《程序员代码面试指南》中,作者采用了两个指针的方法,具体如下。
1设置一个slow指针和一个fast指针,开始时,slow和fast指向链表的头,然后slow每次跳一步,fast每次跳两步。
2如果链表无环,那么fast一定先到终点,直接返回null。
3,如果有环,那么fast和slow一定会再次相遇,当fast和slow相遇的时候,让fast重新回到head的位置,slow不动。接下来,fast指针从每次移动两步改为移动一步,slow依然每次只移动一步。
4 fast指针和slow一定会再次相遇,并且在第一个入环的节点处相遇,证明略。
思路很简单,先是一个每次跳2一个每次跳1,相遇后,把跳2的那个指向head,然后两个每次都只跳1,最后相遇的地方就是要找的地方。
但是这一个证明略。。。
那就自己证明一下。
设入环前需要走m步,环中有n个节点。
并设fast和slow相遇时slow总共走过S,
则有
(S-m)%n = (2S-m)%n (这里是指在环中的位置)
这个公式说明什么 -> S%n = 0
所以把fast放回表头, 然后一步一步走,等他们下次相遇。
注意,他们下次相遇一定是重新从头走的fast指针,走m步正好入环的时候相遇,不可能是在环里走了几圈才相遇,他们走的步长一样,所以肯定是一入环就相遇。
我们要证明的是什么:
就是 fast 走m 意味着slow走了m。而slow原来的位置是(S-m)%n
所以m步以后,slow停留在(S-m)%n+m%n的位置,
由上面可以知道S%n = 0
所以,slow停留在入环的位置。
(为什么会执行把fast放回去,是因为第一次相遇slow停留在(S-m)%n的位置,所以slow 如果再走m步,而S%n = 0,就可以回到环的起点。)