This commit is contained in:
2026-06-21 13:11:31 +10:00
parent 3bce899398
commit 35c362681e
6 changed files with 533 additions and 0 deletions
+101
View File
@@ -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))
}
+63
View File
@@ -0,0 +1,63 @@
package top100liked
import (
"fmt"
"testing"
)
// https://leetcode.cn/problems/merge-two-sorted-lists/description/?envType=study-plan-v2&envId=top-100-liked
type ListNode struct {
Val int
Next *ListNode
}
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
p1, p2 := list1, list2
p := &ListNode{}
res := p
for p1 != nil && p2 != nil {
if p1.Val <= p2.Val {
p.Next = p1
p = p.Next
p1 = p1.Next
} else {
p.Next = p2
p = p.Next
p2 = p2.Next
}
}
for p1 != nil {
p.Next = p1
p = p.Next
p1 = p1.Next
}
for p2 != nil {
p.Next = p2
p = p.Next
p2 = p2.Next
}
return res.Next
}
func Test(t *testing.T) {
input1 := &ListNode{
Val: -9,
Next: &ListNode{
Val: 3,
Next: nil,
},
}
input2 := &ListNode{
Val: 5,
Next: &ListNode{
Val: 7,
Next: nil,
},
}
output := mergeTwoLists(input1, input2)
for output != nil {
fmt.Println(output.Val)
output = output.Next
}
}
+62
View File
@@ -0,0 +1,62 @@
package top100liked
import (
"fmt"
"testing"
)
// https://leetcode.cn/problems/add-two-numbers/description/?envType=study-plan-v2&envId=top-100-liked
type ListNode struct {
Val int
Next *ListNode
}
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
dummy := &ListNode{}
p := dummy
carry := 0
for l1 != nil || l2 != nil || carry > 0 {
sum := carry
if l1 != nil {
sum += l1.Val
l1 = l1.Next
}
if l2 != nil {
sum += l2.Val
l2 = l2.Next
}
p.Next = &ListNode{Val: sum % 10}
p = p.Next
carry = sum / 10
}
return dummy.Next
}
func Test(t *testing.T) {
input1 := &ListNode{
Val: 2,
Next: &ListNode{
Val: 4,
Next: &ListNode{
Val: 3,
Next: nil,
},
},
}
input2 := &ListNode{
Val: 5,
Next: &ListNode{
Val: 6,
Next: &ListNode{
Val: 4,
Next: nil,
},
},
}
output := addTwoNumbers(input1, input2)
for output != nil {
fmt.Println(output.Val)
output = output.Next
}
}
+83
View File
@@ -0,0 +1,83 @@
package top100liked
import (
"fmt"
"testing"
)
// https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/?envType=study-plan-v2&envId=top-100-liked
type ListNode struct {
Val int
Next *ListNode
}
// func removeNthFromEnd(head *ListNode, n int) *ListNode {
// pre := &ListNode{Next: head}
// p := head
// l := 0
// for p != nil {
// l++
// p = p.Next
// }
// p1 := pre
// p2 := pre.Next.Next
// for range l - n {
// p1 = p1.Next
// p2 = p2.Next
// }
// p1.Next = p2
// return pre.Next
// }
// 双指针
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{0, head}
first, second := head, dummy
for range n {
first = first.Next
}
for first != nil {
first = first.Next
second = second.Next
}
second.Next = second.Next.Next
return dummy.Next
}
func Test(t *testing.T) {
input1 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{
Val: 4,
Next: &ListNode{
Val: 5,
Next: nil,
},
},
},
},
}
input2 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: nil,
},
}
output := removeNthFromEnd(input1, 2)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
fmt.Println()
output = removeNthFromEnd(input2, 1)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
}
+89
View File
@@ -0,0 +1,89 @@
package top100liked
import (
"fmt"
"testing"
)
// https://leetcode.cn/problems/swap-nodes-in-pairs/description/?envType=study-plan-v2&envId=top-100-liked
type ListNode struct {
Val int
Next *ListNode
}
func swapPairs(head *ListNode) *ListNode {
if head == nil {
return nil
}
if head.Next == nil {
return head
}
dummy := &ListNode{0, head}
p1, p2, p3 := dummy, dummy.Next, dummy.Next.Next
for {
p1.Next = p3
p2.Next = p3.Next
p3.Next = p2
p2, p3 = p3, p2
for range 2 {
if p3.Next == nil {
return dummy.Next
}
p1 = p1.Next
p2 = p2.Next
p3 = p3.Next
}
}
}
// func swapPairs(head *ListNode) *ListNode {
// dummyHead := &ListNode{0, head}
// temp := dummyHead
// for temp.Next != nil && temp.Next.Next != nil {
// node1 := temp.Next
// node2 := temp.Next.Next
// temp.Next = node2
// node1.Next = node2.Next
// node2.Next = node1
// temp = node1
// }
// return dummyHead.Next
// }
func Test(t *testing.T) {
input1 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{
Val: 4,
Next: nil,
},
},
},
}
input2 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: nil,
},
},
}
output := swapPairs(input1)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
fmt.Println()
output = swapPairs(input2)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
}
+135
View File
@@ -0,0 +1,135 @@
package top100liked
import (
"fmt"
"testing"
)
// https://leetcode.cn/problems/reverse-nodes-in-k-group/description/?envType=study-plan-v2&envId=top-100-liked
type ListNode struct {
Val int
Next *ListNode
}
// 提交记录 3
// 你就说快不快吧
// func reverseKGroup(head *ListNode, k int) *ListNode {
// if k == 1 {
// return head
// }
// nodes := []*ListNode{}
// p := head
// nodes = append(nodes, &ListNode{0, head})
// for p != nil {
// nodes = append(nodes, p)
// p = p.Next
// }
// tmp := nodes[0]
// for i := range (len(nodes) - 1) / k {
// tmp.Next = nodes[(i+1)*k]
// nodes[i*k+1].Next = nodes[(i+1)*k].Next
// for j := range k - 1 {
// nodes[(i+1)*k-j].Next = nodes[(i+1)*k-j-1]
// }
// tmp = nodes[i*k+1]
// }
// return nodes[0].Next
// }
func reverseKGroup(head *ListNode, k int) *ListNode {
dummy := &ListNode{Next: head}
prev := dummy
for {
// 检查剩余节点是否够 k 个
tail := prev
for range k {
tail = tail.Next
if tail == nil {
return dummy.Next
}
}
next := tail.Next // 下一组的起点
// 翻转 [prev, tail] 这 k 个节点
p := prev.Next
var reversedHead, reversedTail *ListNode
reversedTail = p // 翻转后 p 变成尾部
var pre *ListNode
for range k {
tmp := p.Next
p.Next = pre
pre = p
p = tmp
}
reversedHead = pre
// 接回原链表
prev.Next = reversedHead
reversedTail.Next = next
prev = reversedTail
}
}
func Test1(t *testing.T) {
input := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{
Val: 4,
Next: &ListNode{
Val: 5,
Next: nil,
},
},
},
},
}
output := reverseKGroup(input, 2)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
}
func Test2(t *testing.T) {
input := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{
Val: 4,
Next: &ListNode{
Val: 5,
Next: nil,
},
},
},
},
}
output := reverseKGroup(input, 3)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
fmt.Println()
}
func Test3(t *testing.T) {
input := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: nil,
},
}
output := reverseKGroup(input, 2)
for output != nil {
fmt.Print(output.Val, " ")
output = output.Next
}
fmt.Println()
}