u
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package top100liked
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// https://leetcode.cn/problems/linked-list-cycle-ii/?envType=study-plan-v2&envId=top-100-liked
|
||||
|
||||
type ListNode struct {
|
||||
Val int
|
||||
Next *ListNode
|
||||
}
|
||||
|
||||
// 哈希表
|
||||
// func detectCycle(head *ListNode) *ListNode {
|
||||
// _map := make(map[*ListNode]bool)
|
||||
// for head != nil {
|
||||
// if _map[head] {
|
||||
// return head
|
||||
// }
|
||||
// _map[head] = true
|
||||
// head = head.Next
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// 快慢指针法
|
||||
// 核心推导如下:
|
||||
//
|
||||
// 设定变量
|
||||
//
|
||||
// • a = 头节点到入环点的距离
|
||||
// • b = 入环点到相遇点的距离
|
||||
// • c = 相遇点回到入环点的距离(环长 = b + c)
|
||||
//
|
||||
// 推导
|
||||
//
|
||||
// 相遇时:
|
||||
//
|
||||
// • slow 走了 a + b
|
||||
// • fast 走了 a + b + n(b + c)(多走了 n 整圈)
|
||||
// • 因为 fast 速度是 slow 的 2 倍:2(a + b) = a + b + n(b + c)
|
||||
//
|
||||
// 化简得:
|
||||
//
|
||||
// a + b = n(b + c)
|
||||
//
|
||||
// a = n(b + c) - b
|
||||
// a = (n-1)(b + c) + c
|
||||
//
|
||||
// 等式的含义
|
||||
//
|
||||
// a = (n-1)(b + c) + c 意味着:
|
||||
// 从头节点走 a 步 = 从相遇点走 (n-1) 整圈 + 再走 c 步
|
||||
// 而 c 步恰好就是从相遇点回到入环点的距离。
|
||||
//
|
||||
// 所以
|
||||
//
|
||||
// • ptr 从头出发,走 a 步到达入环点
|
||||
// • slow 从相遇点出发,走 (n-1) 圈 + c 步,也到达入环点
|
||||
// • 两者速度相同、同时出发,必然在入环点相遇
|
||||
//
|
||||
// 这就是为什么不需要知道 a、b、c 的具体值,只需要让两个指针同速走,就能找到入口。
|
||||
func detectCycle(head *ListNode) *ListNode {
|
||||
slow, fast := head, head
|
||||
for fast != nil {
|
||||
slow = slow.Next
|
||||
if fast.Next == nil {
|
||||
return nil
|
||||
}
|
||||
fast = fast.Next.Next
|
||||
if fast == slow {
|
||||
p := head
|
||||
for p != slow {
|
||||
p = p.Next
|
||||
slow = slow.Next
|
||||
}
|
||||
return p
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
input := &ListNode{
|
||||
Val: 3,
|
||||
Next: &ListNode{
|
||||
Val: 2,
|
||||
Next: &ListNode{
|
||||
Val: 0,
|
||||
Next: &ListNode{
|
||||
Val: -4,
|
||||
Next: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
input.Next.Next.Next.Next = input.Next
|
||||
fmt.Println(detectCycle(input))
|
||||
}
|
||||
Reference in New Issue
Block a user