當fast == slow時, 兩指針在環中 第一次相遇 。下面分析此時fast 與 slow走過的 步數關係 :
設鏈表共有 a+ba+b 個節點,其中 鏈表頭部到鏈表入口 有 aa 個節點(不計鏈表入口節點), 鏈表環 有 bb 個節點(這裏需要注意,aa 和 bb 是未知數,例如圖解上鍊表 a=4a=4 , b=5b=5);設兩指針分別走了 ff,ss 步,則有:
fast 走的步數是slow步數的 22 倍,即 f = 2sf=2s;(解析: fast 每輪走 22 步)
fast 比 slow多走了 nn 個環的長度,即 f = s + nbf=s+nb;( 解析: 雙指針都走過 aa 步,然後在環內繞圈直到重合,重合時 fast 比 slow 多走 環的長度整數倍 );
以上兩式相減得:f = 2nbf=2nb,s = nbs=nb,即fast和slow 指針分別走了 2n2n,nn 個 環的周長 (注意: nn 是未知數,不同鏈表的情況不同)。
如果讓指針從鏈表頭部一直向前走並統計步數k,那麼所有 走到鏈表入口節點時的步數 是:k=a+nb(先走 aa 步到入口節點,之後每繞 11 圈環( bb 步)都會再次到入口節點)。
而目前,slow 指針走過的步數爲 nbnb 步。因此,我們只要想辦法讓 slow 再走 aa 步停下來,就可以到環的入口。
但是我們不知道 aa 的值,該怎麼辦?依然是使用雙指針法。我們構建一個指針,此指針需要有以下性質:此指針和slow 一起向前走 a 步後,兩者在入口節點重合。那麼從哪裏走到入口節點需要 aa 步?答案是鏈表頭部head。
如果讓指針從鏈表頭部一直向前走並統計步數k,那麼所有 走到鏈表入口節點時的步數 是:k=a+nb(先走 aa 步到入口節點,之後每繞 11 圈環( bb 步)都會再次到入口節點)。
而目前,slow 指針走過的步數爲 nbnb 步。因此,我們只要想辦法讓 slow 再走 aa 步停下來,就可以到環的入口。
但是我們不知道 aa 的值,該怎麼辦?依然是使用雙指針法。我們構建一個指針,此指針需要有以下性質:此指針和slow 一起向前走 a 步後,兩者在入口節點重合。那麼從哪裏走到入口節點需要 aa 步?答案是鏈表頭部head。
實現
funcDetectCycle(head *ListNode)*ListNode {
slow := head
fast := head
for{if fast ==nil|| fast.Next ==nil{returnnil}
slow = slow.Next
fast = fast.Next.Next
if fast == slow{break}}
cur := head
for cur != slow{
cur = cur.Next
slow = slow.Next
}return cur
}