找出帶環單向鍊錶的環入口(交點)

2021-06-22 16:39:03 字數 1668 閱讀 1507

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

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

土方法很多,但是比較好的目前就那麼乙個:一開始設定兩個指標都指向表頭,其中乙個每次(一步)前進乙個節點的叫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~

鍊錶(找出環的入口)

題目 找出鍊錶中環的開始位置 題解 使用快慢指標,當快指標不為空時,快指標走兩步,慢指標走一步 判斷是否相遇 相遇的話,讓快指標從頭再和慢指標一塊走,直到相遇 鍊錶中環的入口 給乙個鍊錶,若其中包含環,請找出該鍊錶的環的入口結點,否則,輸出null。public listnode entrynode...

找出鍊錶環的入口

問題 給乙個鍊錶,若其中包含環,請找出該鍊錶的環的入口結點,否則,輸出null。分析 快慢指標 公式推導 code public class listnode public listnode entrynodeofloop2 listnode phead else 沒找到環 if fast null...

判斷鍊錶是否帶環,以及環的入口

給出乙個鍊錶,先判斷鍊錶是否帶環,如果帶環,求出環的入口。判斷是否帶環 用快慢指標。快指標每走兩步,慢指標走一步,如果兩者在某個點處相 遇,則鍊錶帶環。下邊給出函式的實現 typedef struct linknode linknode,plinknode typedef struct linkli...