連結串列找環方法證明(拒絕誤人子弟)

DoubleFJ發表於2018-10-23

個人部落格:DoubleFJ の Blog

前言

今天又想起來了這個問題,之前最開始是在其他論壇中看到有人說起了這個面試題。

當時只是翻了下,大致瞭解瞭如何判斷連結串列中是否有閉環,用兩個快慢指標解決,但是沒有了解如何去找到閉環開始的節點。

剛上網搜了下,一群垃圾博主亂七八糟胡說八道,就知道從其他地方複製貼上,都不過腦子的。誰說較快指標一定就是第二次在環上移動就能遇到較慢指標的,我這麼個渣渣都能一眼看出來毛病一群人還複製貼上都說 2,你們還真是 2!

問題描述

一條連結串列如何判斷是否有環?若是有環那怎麼找到連結串列環的入口?

解決思路

  • 先判斷是否有環

思路: 用快慢兩個指標分別從連結串列頭開始,慢指標 -> next,快指標 -> next -> next,這樣如果有環那快指標務必會跑到慢指標後面,隨即兩者之間的距離一次會縮小一步,最終相遇。若是未相遇且快指標的 next 為 null,則說明連結串列無環。

  • 若是有環怎麼找到環入口

連結串列中有閉環即快慢兩指標相遇了,見下方的手工圖:

連結串列閉環

一切清晰明瞭。讓我們再來捋一捋。

當兩指標在 P 點相遇,我們可列出如下等式:

2(L+x) = L+x+n*H        (n >= 1) // n 為快指標在閉環上的圈數
=> 2L+2x = L+x+n*H      (n >= 1)
=> L = n*H-x            (n >= 1)
=> L = n*(H-x)+(n-1)x   (n >= 1)

到這裡,是不是有種扒光了的快感,哈哈。
網上許多部落格就是把 n 預設當成了 1,實則不然。

思路: 故我們可以這樣做,當 l1 與 l2 相遇時,再來一個 l3 指標從連結串列頭開始,而 l1 繼續走,l2 就可以終結其使命沒必要繼續走了。此時 l1 和 l3 指標都是指向其 next。當 l3 指標到達環入口時,l1 也必然到達了環入口,即 l1 和 l3 指標會在環入口相遇,從而可求得入口位置。

參考部落格

相關文章