算法推導
image
當
hare
的移動速度是tortoise
的 2 倍,設起始點到環的入口的距離是
T
,環的長度是C
,當
tortoise
第一次走到環的入口entry point
時,我們假設這是tortoise
與hare
之間的在環上的距離是r
,從
start point
開始出發到tortoise
第一次走到環的入口時,hare
移動的距離是 T + r + k*C,k >= 0
,又因為,
hare
移動的速度是tortoise
的兩倍,且這時tortoise
移動的距離是T
,所以hare
移動的距離是 2T。得到等式 A
T + r + k*C = 2T,k >= 0
簡化得到等式 B
r + k*C = T,k >= 0
[圖片上傳失敗...(image-1940ba-1559799507418)]
當 tortoise 第一次走到環的入口entry point
時,而這時tortoise
與hare
之間的距離是 r,
那么如果tortoise
現在就不繼續移動的話,hare
還需要往前走C-r
才能追上tortoise
。
但是hare
在往前追趕tortoise
的時候,tortoise
也在移動,而hare
的移動速度是tortoise
的兩倍,
所以hare
可以追上tortoise
,并且需要往前走2*(C-r)
才能追上tortoise
。
image
當hare
移動了2*(C-r)
的距離追上tortoise
的時候,tortoise
從相對于環的入口entry point
移動了C-r
。
所以,在tortoise
與hare
第一次在環上相遇時,環的入口entry point
到這個點meet point
的距離是C-r
, 而從這個相遇點meet point
再往前移動r
,就又回到了環的入口entry point
。
在hare
與tortoise
第一次相遇的這個時候,將hare
從meet point
重新放到起始點start point
,tortoise
仍放在這個相遇點meet point
,
然后讓它們以相同的速度開始移動,
根據等式 B r + k*C = T,k >= 0
,
tortoise
和hare
必然會在環的入口點entry point
再次相遇。
入口entry point
找到后,就能很容易得到T
,
然后入口entry point
,讓tortoise
停下,hare
繼續跑一圈,就能得到 C
。
算法應用
- 鏈表有環檢測
兩個指針,慢指針移動速度為 1,快指針移動速度為 2,判斷兩個指針是否相遇 - 找出有環鏈表的入口節點
當兩個指針相遇時,將其中一個指針重新放到鏈表頭,然后讓兩個指針移動速度都為 1,當兩個指針再次相遇,就找到了有環鏈表的入口節點 - 計算環長度
在入口節點放置兩個個指針,一個指針不動,一個指針移動速度為 1,兩個指針相遇,就可計算出環的長度
算法實現
golang
- 鏈表有環檢測
leetcode 141
/*
* @lc app=leetcode id=141 lang=golang
*
* [141] Linked List Cycle
*/
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
if head == nil {
return false
}
t, h := head, head
started := false
for h != nil && h.Next != nil {
if t == h {
if started {
return true
} else {
started = true
}
}
t = t.Next
h = h.Next.Next
}
return false
}
- 找出有環鏈表的入口節點
leetcode 142
/*
* @lc app=leetcode id=142 lang=golang
*
* [142] Linked List Cycle II
*/
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func detectCycle(head *ListNode) *ListNode {
var cycPoint *ListNode
if head == nil {
return cycPoint
}
t, h := head, head
started := false
hasCycle := false
for h != nil && h.Next != nil {
if t == h {
if started {
hasCycle = true
break
} else {
started = true
}
}
t = t.Next
h = h.Next.Next
}
if hasCycle {
h = head
for h != nil && t != nil {
if h == t {
cycPoint = h
break
}
h = h.Next
t = t.Next
}
}
return cycPoint
}
歡迎轉載,請注明出處~
作者個人主頁