找出带环单向链表的环入口(交点)
其實這個問題已經被問爛了,但是之前沒有想透,今天算是解決得差不多。
找環(huán)的入口這個問題,其實是建立在另外一個問題之上的——判斷單向鏈表是否有環(huán)
土方法很多,但是比較好的目前就那么一個:一開始設置兩個指針都指向表頭,其中一個每次(一步)前進一個節(jié)點的叫p1,另外那個每次(一步)前進兩個節(jié)點的叫p2 。p1和p2同時走,當其中有一個遇到null,就證明鏈表沒有環(huán)。如何某個時刻(假設走了n步之后),p1和p2指向的地址相同,那么鏈表就是有環(huán)的。
接著很自然的問題就是,環(huán)的入口在哪里?
我是先看了答案,再去推導的,但是為了各位能夠順著思路,我下面就嘗試用順推的方式來展現(xiàn)結果,但是這樣做有個不好的地方,可能有人在看完答案后會想:“我去,怎么可能想到”,這個時候由于直接看推導了,連自己推導的機會都沒有,所以我建議各位先自己嘗試想一下,想不出的話,你可以選擇兩條路:
1. 直接看答案,然后推導,答案在此【在p1和p2重合后,設置一個p3指向表頭,然后p1和p3每次同時行走一步,每步前進一個節(jié)點,等到p1和p3重合時,重合的位置就是環(huán)的入口】,反選就可以看到;
2. 看順推的過程,不知道答案,但是自己看了后也沒有辦法從答案推導了,因為我已經告訴你推導方法了……要走這條路的請往下拉吧……
先看下面這張圖:
我們設鏈表的無環(huán)的部分長度為L1,即有L1個節(jié)點,注意,這個L1是包括環(huán)的入口節(jié)點的。然后讓環(huán)的長度是L2,這個L2也是包括環(huán)的入口節(jié)點。這個時候,p1和p2的交點如圖所示,交點距離環(huán)的入口節(jié)點為a(從入口節(jié)點沿著行走方向走到交點),即在環(huán)的入口節(jié)點后面的第a個節(jié)點,就是交點,我用紅色標記出a。
然后我們來考察一下L1,L2,a,以及n(n是走過的步數(shù),不是走過的節(jié)點數(shù),p1一步一個節(jié)點,p2一步兩個節(jié)點)的關系。
忘記說一點了,我們可以明確的是,p1在進入環(huán)后,走了不到一圈就在交點處和p2重合,為什麼肯定沒有走完一圈?因為p1在進入環(huán)的時候,p2和p1之間的距離(沿著行走方向)至多為 L2-1,不可能超過L2-1,因為環(huán)的大小也才只有L2 。p2追趕p1,最多只需要走L2-1步,因為每走一步,p1和p2的相對距離減小1,那么p1最多只走了L2-1步,就是最多只經過了L2-1個節(jié)點,不可能走完一圈。
現(xiàn)在可以列公式了:
L1+a=n ? ? ? ? ? ? ? ? ? #1 ? //n是p1走過的節(jié)點數(shù)
L1+k*L2+a=2*n ? ? #2 ? //2*n這個是p2走過的節(jié)點數(shù),其中的k表示p2可能在環(huán)里面走了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)表示的是交點與環(huán)入口的距離(從交點沿著行走方向到環(huán)入口),然后(k-1)是>=0的,因為p2在環(huán)中至少繞了一圈,這樣我們就發(fā)現(xiàn):L1的長度 = 環(huán)長度的整數(shù)倍 + 交點與環(huán)入口的距離
也就是說,p1再走L1步就可以達到環(huán)的入口。問題是L1不是已知的,沒關系,在表頭設置一個p3指針,p3每步前進一個節(jié)點。讓p1和p3同時走,每次走1步,等p3和p1重合了,就是到了環(huán)口的位置了。Problem solved~
?
總結
以上是生活随笔為你收集整理的找出带环单向链表的环入口(交点)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android launcher 相关
- 下一篇: “棱镜”折射出了什么