1. 程式人生 > >Floyd判圈演算法(判斷是否有環)

Floyd判圈演算法(判斷是否有環)

用於判斷是否存在環,求解環的起點,求解環的周長

時間複雜度:O(n)

演算法原理:龜兔解法的基本思想可以用我們跑步的例子來解釋,如果兩個人同時出發,如果賽道有環,那麼快的一方總能追上慢的一方。進一步想,追上時快的一方肯定比慢的一方多跑了幾圈,即多跑的路的長度是圈的長度的倍數。

基於上面的想法,Floyd用兩個指標,一個慢指標(龜)每次前進一步,快指標(兔)指標每次前進兩步(兩步或多步效果是等價的,只要一個比另一個快就行,從後面的討論我們可以看出這一點)。如果兩者在連結串列頭以外的某一點相遇(即相等)了,那麼說明連結串列有環,否則,如果(快指標)到達了連結串列的結尾,那麼說明沒環。

環的檢測從上面的解釋理解起來應該沒有問題。接下來我們來看一下如何確定環的起點,這也是Floyd解法的第二部分。方法是將慢指標(或快指標)移到連結串列起點,兩者同時移動,每次移動一步,那麼兩者相遇的地方就是環的起點。

假設起點到環的起點距離為m,已經確定有環,環的周長為n,(第一次)相遇點距離環的起點的距離是k。那麼當兩者相遇時,慢指標移動的總距離為i,i = m + a * n + k,因為快指標移動速度為慢指標的兩倍,那麼快指標的移動距離為2i,2i = m + b * n + k。其中,a和b分別為慢指標和快指標在第一次相遇時轉過的圈數。我們讓兩者相減(快減慢),那麼有i = (b - a) * n。即i是圈長度的倍數。利用這個結論我們就可以理解Floyd解法為什麼能確定環的起點。將一個指標移到連結串列起點,另一個指標不變,即距離連結串列起點為i處,兩者同時移動,每次移動一步。當第一個指標前進了m,即到達環起點時,另一個指標距離連結串列起點為i + m。考慮到i為圈長度的倍數,可以理解為指標從連結串列起點出發,走到環起點,然後繞環轉了幾圈,所以第二個指標也必然在環的起點。即兩者相遇點就是環的起點。

得出環的起點後就可以再跑一圈得出周長了

可以用於一些存在迴圈的題目,如UVA 11549