如果你曾经想过要参加面试,像我一样,你一定看过这个问题:如何判断链表中存在环路。(我不太清楚这个问题的应用在哪里,烦请各位读者能够提示一下。)
先简单说一下我之前看到的方法。
方法一:蛮力法。
方法二:在链表中增加一个域visited,初始化都为0,从链表的头部开始走,每走过一个链表就标记visited为1,如果要访问的下一个节点的visited域为1,那么证明链表中有环。
方法三:如果不能增加域,可以设置一个数组,将已经访问的链表节点依次放入到数组中,在访问下一个节点时,如果这个节点的地址已经在数组中,那么也能证明链表中有环。
进入正题之前,先简单说一下今天的面试。今天下午我参加面试的时候也被问到了这个问题,面试官是个南开的MM。似乎她也意识到诸如此类的问题已经在网上司空见惯,所以就试探性的问我是不是之前已经在网上看到了方法。我很老实,回答:嗯。我俩相视而笑。
然后,她又问我一个问题:如何找到一个链表的中间元素?我想了想,灵光一闪,说:设置两个指针p和q,p一次走一下,q一次走两下,这样当q走到链表的尾部的时候,p应该正好走到链表的中间(我当时很佩服我自己。。。)。那个MM笑了一下,表示赞同,接下来随口的一句话把我带入了漩涡:嗯,刚才那个判断链表是否有环的问题也可以用这个方法。顿时,我脸上呈现出迷茫的表情,好奇心驱使着我问道:真的?MM一看我竟然不知道这个方法,说:哦,原来你不知道啊!正好,你想想用你刚才说的方法解决一下链表有环的问题。同志们,好奇心害死猫啊!
然后我就囧了,折腾了半天,画了个链表,在上面试着画了一下,发现如果链表有环,有可能q会追上p,相当与长跑中的套圈。但是,有一个问题:p是不是一定会和q重合?
这个问题看起来有些复杂,我们现在来抽象一下,这个问题不是很难。
假设此时p点刚刚进入到链表中的环中,q在环中的某一个位置,如图所示。
设t时间后,p和q在环中的某一点相遇,初始时p和q相隔k个节点(0<=k<=n-1,其中n为环中的节点数;图中p和q相隔3个节点,而不是2个:因为假如q不动,p需要经过3步移动才可以和q重合),那么可得:
t(mod n) = k + 2t(mod n)
那么,对任意的正整数m,使得:t + mn = k + 2t
那么显然此时 t = mn-k,m>=1。
靠!原来这么简单。。。