经典面试题之链表回路问题

问题描述:给定一个单链表,在O(1)空间复杂度内判断链表是否有回路。

解答:

如图,可能发生的情况

​​

即判断是否会出现上述的情况。

当然还有一些特殊情况,例如:

​​

因此很多同学直接判断尾指针是否会指向头结点,这样的算法是不对,或者说是考虑不周全的,假如共有n个结点,那么上述的概率只有1/n,也就是仅仅考虑到了n种可能情况的一种情况而已。

算法思想如下:

采用两个指针,一个指针每次走一步,两外一个指针每次走两步

若在走两步的指针终止之前等于第一个指针那么,表示链表有回路,否则表示

没有回路。


这个思想很简单,简单比如来说,就好比判断现实世界上的一条道路,判断这个道路是否会有回路。

让一个人跑得快一些,一个人跑得慢一点,如果存在回路的话,快的一个人肯定会在某个时间追上

跑得慢得一个人。


如图所示:

​​

假如有回路的话,且b每次走两步,而a每次走一步,所以b必定会超过a。但是这里有一个问题,b是会超过a,但是会不会产生一种情况:

每次b都跳过a,但是不会和a同步呢?

如果这种情况出现,那么该算法就是有问题的,因为在一个循环里,b每次都跳过a的话,还是没有终止条件,即无法判断出链表是否出现循环。

下面给出问题的严格证明(我发现我的确够无聊了。。。。)

先举个最简单的例子。考虑只有两个节点的情况:

​​

假如a每次走一步,b每次走两步,可以发现,b会一直在第一个点不动,而a会在两个点之间来回走动,明显会相遇。

考虑三个结点的情况:

​​

同上述条件,a和b依然会在第一个点相遇。

我们给出一个形式化证明:

假设经过了某一系列的步数之后,a和b相差一个,假设b在a之前,那么在经过固定的同步数之后,b会在a前面两个,以此类推,b会在若干步之后遇上a。