在《编程之美》上看到这个题,自己想了想,没啥好的方法,便去网上搜了搜。得知这个题好像源自《c专家编程》,并且不知最初哪位大神给出了一种巧妙的方法。即设置两个指针slow和fast,slow每次走一步,fast每次走两步,如果在某一步相等,则说明存在环。这种方法网上转载或者自己实现的比较多。
至于如何证明存在环时,slow和fast一定会相遇,可参见http://www.cnblogs.com/persistentsnail/p/3294917.html,我没看懂。在网上搜索时,看到一条评论,说链表是走两步也是一步一步走的,所以只要fast追上了slow,就一定会相遇。这就相当于两人在操场跑圈,一个跑得快,一个跑得慢,跑得快的人第一次追上跑得慢的人便相遇了。具体在程序中,相当于每次循环时,slow=slow->next后,fast=fast->next,fast与slow比较,fast=fast->next,fast与slow比较,注意得除了第一次循环,不然都从开始出发,都走一步,然后比较,那一定会相等。此时fast另外可不可以slow走2步,fast走5步,或者其他组合,以及要不要求slow和fast走的步数互为素数等问题,数学功底不行,搞不懂,可以参见http://www.chinaunix.net/old_jh/23/410637.html。
对于求环的开始结点,http://www.cppblog.com/humanchao/archive/2012/11/12/47357.html中的解法是用公式分析,并先给出一个结论----当fast若与slow相遇时,slow肯定没有走遍历完链表。这个是不对的,比如1 2 3 4 1 2 3 4。。。都从1出发,最终相遇时slow走过的路径为1 2 3 4 1,fast走过的路径为1 3 1 3 1。后边的分析我就没看了。
如何求环的开始结点?一种思路是使用一个哈希表,把遍历过的指针存哈希表里,每次检测哈希表中是否存在当前指针。这样可以轻易解决是否存在环,以及求环的开始结点的问题。但是需要用到哈希表。