這是之前朋友出的一道題目,感覺不錯,就拿來分享一下。
問題如下:
乙個單向鍊錶,怎麼判斷他是否存在環?
圖示:
對於最簡單的做法就是:
用乙個指標走一圈,如果重複遇到其他任何乙個指標,則證明有環。
但是這樣做的問題就是:
單指標需要留下腳印,會弄髒鍊錶資料,而如果不能髒資料的話,就需要增加乙個容器,並且增加查詢的開銷。
有沒有更好的方法呢?有的,定義一對快慢指標分別為ptr_fast,ptr_slow,ptr_slow走一步,ptr_fast走兩步,如果ptr_slow和ptr_fast最終能相遇,那麼證明有環。
解釋如下:
畫圖:
設步長分別為x和y,鍊錶回環結點數為n,非環回環為m
設經過t次跨步,則只要xt和yt對n同餘並且xt和yt都大於m就可以相遇(假設x>y)
xt-yt=pn
yt>m
得到:
t=pn/(x-y) > m/y(只需pn可整除(x-y))
指標移動次數為(x+y)t=(x+y)/(x-y)*pn
而要想pn永遠整除(x-y),那麼x-y=1即可。在x-y固定為1的情況下x+y越小,則移動次數越少,也即指標比較次數越少,所以x為2,y為1。
其實還有第二個問題,即,假設ptr_fast在ptr_slow走完一圈前相遇,那環的長度和鍊錶的長度分別為多少。(注意:以下方法是有問題的,如果ab足夠長的話,那可能是在好幾圈之後相遇的)
我們根據第乙個問題的結論,假設ptr_fast和ptr_slow在c點相遇。
圖示:
假設x是速度,t是時間。
則對ptr_slow:
ab+bc = x * t
對ptr_fast:
ab+bc+cb+bc = 2x*t
所以得出:
cb + bc = ab + bc
即: cb = ab
所以環的長度就求出來了,即bc+cb = bc + ab = ptr_slow走的路程。
那鍊錶的長度呢?
現在已經有了ab+bc的長度,只需要知道ab或者cb的長度即可:
再建立乙個指標ptr_new,讓ptr_new從head開始,和ptr_slow同時開始走,都是每次一步,由於ab == cb,所以他們相交的地方就是b點。所以即可得到整個鍊錶的長度。
如果不是在慢指標走一圈內相遇,我還沒有想到有算出環的長度和鍊錶長度的方法,大家如果有答案歡迎告知~~
鍊錶的游標實現 一道演算法題
輸入包含多組資料。每組資料佔一行,包含不超過100000個字母 下劃線 字元 或 者 其中字元 表示home鍵,表示end鍵。輸入結束標誌為檔案結束符 eof 輸 入檔案不超過5mb。對於每組資料,輸出一行,即螢幕上的悲劇文字。樣例輸入 this is a beiju text 樣例輸出 beiju...
判斷兩個鍊錶能否合併 一道演算法題
有兩個單向鍊錶 鍊錶長度分別為 m,n 這兩個單向鍊錶有可能在某個元素合併,如下圖所示的這樣,也可能不合併。現在給定兩個鍊錶的頭指標,在不修改鍊錶的情況下,如何快速地判斷這兩個鍊錶是否合併?如果合併,找到合併的元素,也就是圖中的 x 元素。請用 或 偽 描述演算法,並給出時間複雜度和空間複雜度 兩個...
如何判斷鍊錶是否有環 鍊錶是否有環的判斷
對於鍊錶是否存在環,有三個問題需要考慮 1.是否有環 2.入環節點 3.環的長度 第一種方法快慢指標法,也稱之為龜兔演算法,設定兩個指標,慢指標和快指標。最開始均指向鍊錶的頭節點,之後,快指標每次後移兩個節點,慢指標每次後移乙個節點。1.如果快指標指向空,則鍊錶無環 2.若快指標和慢指標再次指向乙個...