赞
踩
(1)设两个指针为P1、P2,P1的移动速度为每次移动m个节点,P2的移动速度为每次移动n个节点,0 < m < n。P1和P2初始都指向链表头节点。另设链表中环中的节点为L1(L1 >= 2),链表剩余节点个数为L2(L2 >= 0)。
(2)我们利用假设法来证明,即假设会相遇,那么接下来我们要做的就是能否来找到一个次数K,这个K使下面两个条件a和b同时成立
a:(L2 + n*K) - (L2 + m*K) = h*L1 => K * (n - m) = h * L1 => h = K*(n-m)/L1(h为不小于1的整数,代表P2节点比P1节点在环中多走的圈数)。如果相遇了,那么P2节点肯定比P1节点在环中多走了若干圈,所以推出这个等式成立;如果这个等式成立,也能表示P1和P2肯定能同时走到同一个节点上。
b:m*K >= L2 => K >= L2/m,这个条件之所以存在,是因为P1和P2肯定是在环内相遇,环外由于速度不同,是不可能相遇的,那么P1肯定进入环内了,那么环外的节点肯定都经历了。
(3)在m、n、L2、L1给定的条件下,不管这四个变量的值为多少,我们都能找到符合a和b的一个最小整数,就是我们要找的次数K。比如m = 2,n= 3,L1 = 4,L2 = 3,我们要找的K满足的条件是K/4为不小于1的整数,并且K >= 1.5,可得满足条件的最小整数为4,即同时移动4次,P1和P2会相遇。为了便于理解,我们以此为例,画图说明一下移动过程,如下图所示:
有上面可知最终的移动次数K满足两个条件
(1) h = (n-m)/L1 * K
(2) K >= L2/m;
我们先考虑最坏情况下的移动次数,m=1时,条件2所要求的K的最小取值范围是最大的,即K >= L2.。我们再对条件1的等式进一步化简:h = t/s*K,其中t/s是(n-m)/L的最简公约式,则1 <= s <= L1。如果s >= L2,那么K = s即可满足条件,那么K <= L1 <= L;如果s < L2,那么K = (u + 1)*sj即可,u为不超过L2/s的最大整数,那么K = (us + s) <= (L2 + s) <= (L2 + L1) = L。上面我们讨论的是最坏情况即m = 1的情况,K的取之仍会不超过L,那么可知其他情况下,K的取值也定会不超过L,所以算法时间复杂度是O(L)。
该问题的算法是基于问题一的,但是对两指针的移动速度有了一个限制,就是两指针速度最好相差1,即n-m=1,两个指针相遇之后,我们只需把P1初始化为头节点,P2的位置保持不变,然后两指针同时移动且每次均移动一个节点,那么这两个指针会再次相遇并且相遇时所处的节点就是环的头节点。注意,该问题的解法中有两次相遇,第一次是为了判断存在环,第二次是为了定位环的头节点。
证明过程:我们设两指针第一次相遇的时候,指针P1在环内所走的圈数是q1,指针P2在环内所走的圈数是q2,另设第一次相遇所处的节点位置离环的头节点的距离为d,那么可得到下面两个等式:
m*K = L2 + q1*L1 + d;
n*K = L2 + q2*L1 +d;
推导出n*(L2 + q1*L1 + d) = m*(L2 + q2*L1 +d) => d = (m*q2-n*q1)/(n-m)*L1 - L2,看到这个等式,我们设想,如果(m*q2-n*q1)/(n-m)为整数,那么如果P2再走L2步,刚好可以走到环的头节点,而把P1初始化为链表的头节点,那么P1走L2步,也能刚好走到环的头节点。如何能让(m*q2-n*q1)/(n-m)为总是为整数呢,那就是让n-m=1。
闲来无事,对上述两个问题的解法加以证明,也好做到用起来心中无疑虑。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。