首先有三点要说明:
1)在快指针追击慢指针时,如何保证快指针不会跨过慢指针而不会重合?
快指针总是能和慢指针重合,为什么?因为如果假如真的“跨过了”,那么慢指针在i位置,快指针在i+1位置。但是考虑上一步,慢指针必定在i-1位置,快指针也在i-1位置,所以在上一步时已经重合了!
2)为什么相遇时通过重置慢指针,然后让快慢指针以相同速度前进,再次相遇就是环的开始点?
这就要分析一下走的过程了。因为快指针走的速度是慢指针的两倍,那么如果慢指针走p步,则快指针走了2p步。现在假设环的开始节点距离head节点有k个距离,则当慢指针走了k步时,慢指针正好到环的开始节点D,与此同时,快指针也走了2k步,前k步走在环外,后k步走在环内。由于k可能比环的长度还大,所以我们让k = k % LOOP_SIZE。
现在有如下的结论:
- 慢指针在环的开始处
- 快指针在超前环k步的位置上
- 慢指针落后k步于快指针
- 快指针落后 LOOP_SIZE - k 步于慢指针!
- 快指针以慢指针2倍的速度追击慢指针。或者说快指针以1步的相对速度追击相对静止的慢指针。则需要LOOP_SIZE-k 才能追上慢指针。在I位置追上。
D -> I 的距离是 LOOP_SIZE - k, I -> D 的距离是k,这段距离恰好和A->D的距离相同,都是k !!!那么把慢指针放在head节点A,然后两个指针以相同速度前进,相遇处就是环的开始节点。
3)一个推论:快慢指针第一次相遇的地方和head的距离是环长度的整数倍。
假设相遇处离环开始点相距x个点,环长度为n个点
慢指针:k+qn+x=m (1)
又有2m-m=m=pn (2)
有(1),(2)可得:k+qn+x=pn
所以k+x = (p-q)n,即相遇处离head的距离为环长的整数倍.
所以将其中一个指针移至head,同时两指针以相同速度再次相遇即为环的开始处.
1.如何判断一个链表中有环
使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。
就是所谓的追击相遇问题:
2.求有环单链表的环长
在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。
设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:
环长=2*len-len。
3.求有环单链表的环连接点位置
第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。
参考网址:http://www.cnblogs.com/xudong-bupt/p/3667729.html
http://www.2cto.com/kf/201403/282309.html