關於單向鏈表的有環判斷

單向鏈表是否有環,目前從其他博文中看到兩種方式:
1. 雙層遍歷
若從前向後遍歷,當鏈表有環時,會陷入死循環。因此應從頭節點開始,外層循環向後遍歷,內層循環由當前節點 p 向前遍歷,當遍歷過程中發現某節點 q 與當前節點的下一節點相等,即 q == p.next 時,說明有環(因爲無環的話,一個在前一個在後不可能相等),且 p.next 節點即爲環入口。
2. 快慢雙指針
快指針每次移動兩個節點,慢指針每次移動一個節點。
問題就在快慢雙指針這兒:
關於推導公式其他博文也圖文並茂講的比較清楚,除了爲什麼“第一次相遇時,慢指針一定沒走完一圈,或者恰好走完一圈”。這個問題可以通過寫代碼跑一下,發現的確如此,但這種舉例的方式卻無法證明數學問題。
此時,可以從慢指針入環時開始看,假如環周長爲 l,慢指針入環時快指針的位置爲 k(0 <= k < l),此時時間 t 爲 0。則 k 可以視爲在這一圈快指針領先慢指針的長度(強調“這一圈”,是因爲有可能快快指針已經轉了若干圈了),同樣,l - k 也可視爲下一圈快指針落後慢指針的長度。因此,當快指針與慢指針相遇時,慢指針走的距離爲 t,快指針走的舉例爲 2t。這時,快指針若要追上慢指針,則需要首先走完 l - k 的距離,到達環入口,再走 t 的距離追上慢指針,即 2t = l - k + t,推導出 t = l - k,也就是說時間爲周長減去快指針起始位置,因 l - k 的範圍爲 0 ~ l,故 t 的範圍以及追及時慢指針的位置也是 0 ~ l,未走完一圈。
綜上,便可得到快慢指針在環中相遇時,慢指針未走完一圈的結論了。再之後就可以直接領此結論,進行下一步推導。

給自己的話:想法雖瑣碎,但記錄下來,總好過想搞大事情卻什麼也沒做。
相關博文已經夠細節,日後需整理一下這個問題的思路,再引用其他文章鏈接就好了。只是不知道誰會和我有一樣的疑問。另外,倒是可以寫個 Java 實現。
注:當快指針速度爲 3 時,是否仍可判斷呢?答案是不能,舉特例來看,假如環大小爲 4,即分別有節點 0 / 1 / 2 / 3,當慢指針在 0 上,而快指針在 3 上時,下次移動,慢指針在 1 上,快指針在 2 上;其實,反向思考,當環大小爲 4,每次移動三個也就相當於每次向後移動 1 個,即快指針路徑爲 3 → 2 → 1 → 0,慢指針路徑爲 0 → 1 → 2 → 3,每次都恰好擦肩而過,因此永遠無法判斷有環。
參考記錄:https://blog.csdn.net/wuzhekai1985/article/details/6725263

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章