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

其實這個問題已經被問爛了,可是以前沒有想透,今天算是解決得差很少。指針

找環的入口這個問題,實際上是創建在另一個問題之上的——判斷單向鏈表是否有環方法

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

接着很天然的問題就是,環的入口在哪裏?鏈表

我是先看了答案,再去推導的,可是爲了各位可以順着思路,我下面就嘗試用順推的方式來展示結果,可是這樣作有個很差的地方,可能有人在看完答案後會想:「我去,怎麼可能想到」,這個時候因爲直接看推導了,連本身推導的機會都沒有,因此我建議各位先本身嘗試想一下,想不出的話,你能夠選擇兩條路:img

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~

相關文章
相關標籤/搜索