找出帶環單向鏈表的環入口(交點)


其實這個問題已經被問爛了,但是之前沒有想透,今天算是解決得差不多。

找環的入口這個問題,其實是建立在另外一個問題之上的——判斷單向鏈表是否有環

土方法很多,但是比較好的目前就那么一個:一開始設置兩個指針都指向表頭,其中一個每次(一步)前進一個節點的叫p1,另外那個每次(一步)前進兩個節點的叫p2 。p1和p2同時走,當其中有一個遇到null,就證明鏈表沒有環。如何某個時刻(假設走了n步之后),p1和p2指向的地址相同,那么鏈表就是有環的。

接着很自然的問題就是,環的入口在哪里?

我是先看了答案,再去推導的,但是為了各位能夠順着思路,我下面就嘗試用順推的方式來展現結果,但是這樣做有個不好的地方,可能有人在看完答案后會想:“我去,怎么可能想到”,這個時候由於直接看推導了,連自己推導的機會都沒有,所以我建議各位先自己嘗試想一下,想不出的話,你可以選擇兩條路:

1. 直接看答案,然后推導,答案在此【在p1和p2重合后,設置一個p3指向表頭,然后p1和p3每次同時行走一步,每步前進一個節點,等到p1和p3重合時,重合的位置就是環的入口】,反選就可以看到;

2. 看順推的過程,不知道答案,但是自己看了后也沒有辦法從答案推導了,因為我已經告訴你推導方法了……要走這條路的請往下拉吧……










先看下面這張圖:


我們設鏈表的無環的部分長度為L1,即有L1個節點,注意,這個L1是包括環的入口節點的。然后讓環的長度是L2,這個L2也是包括環的入口節點。這個時候,p1和p2的交點如圖所示,交點距離環的入口節點為a(從入口節點沿着行走方向走到交點),即在環的入口節點后面的第a個節點,就是交點,我用紅色標記出a。

然后我們來考察一下L1,L2,a,以及n(n是走過的步數,不是走過的節點數,p1一步一個節點,p2一步兩個節點)的關系。

忘記說一點了,我們可以明確的是,p1在進入環后,走了不到一圈就在交點處和p2重合,為什麼肯定沒有走完一圈?因為p1在進入環的時候,p2和p1之間的距離(沿着行走方向)至多為 L2-1,不可能超過L2-1,因為環的大小也才只有L2 。p2追趕p1,最多只需要走L2-1步,因為每走一步,p1和p2的相對距離減小1,那么p1最多只走了L2-1步,就是最多只經過了L2-1個節點,不可能走完一圈。

現在可以列公式了:

L1+a=n                   #1   //n是p1走過的節點數

L1+k*L2+a=2*n     #2   //2*n這個是p2走過的節點數,其中的k表示p2可能在環里面走了k圈,k>=1

由#2式減去#1式,有:

k*L2 = n                   #3

同時由#1和#3得到:

L1+a = k*L2            #4

接着由#4就得到了如下式:

L1 = k*L2 - a = (k-1)*L2 + (L-a)

得到這條式子就撥得雲開見月明啊有木有,因為(L-a)表示的是交點與環入口的距離(從交點沿着行走方向到環入口),然后(k-1)是>=0的,因為p2在環中至少繞了一圈,這樣我們就發現:L1的長度 = 環長度的整數倍 + 交點與環入口的距離

也就是說,p1再走L1步就可以達到環的入口。問題是L1不是已知的,沒關系,在表頭設置一個p3指針,p3每步前進一個節點。讓p1和p3同時走,每次走1步,等p3和p1重合了,就是到了環口的位置了。Problem solved~


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM