diff --git a/top-100-liked/26/26_test.go b/top-100-liked/26/26_test.go new file mode 100644 index 0000000..824d76b --- /dev/null +++ b/top-100-liked/26/26_test.go @@ -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)) +} diff --git a/top-100-liked/27/27_test.go b/top-100-liked/27/27_test.go new file mode 100644 index 0000000..06de6ea --- /dev/null +++ b/top-100-liked/27/27_test.go @@ -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 + } +} diff --git a/top-100-liked/28/28_test.go b/top-100-liked/28/28_test.go new file mode 100644 index 0000000..9ccab7c --- /dev/null +++ b/top-100-liked/28/28_test.go @@ -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 + } +} diff --git a/top-100-liked/29/29_test.go b/top-100-liked/29/29_test.go new file mode 100644 index 0000000..163df75 --- /dev/null +++ b/top-100-liked/29/29_test.go @@ -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 + } +} diff --git a/top-100-liked/30/30_test.go b/top-100-liked/30/30_test.go new file mode 100644 index 0000000..1867435 --- /dev/null +++ b/top-100-liked/30/30_test.go @@ -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 + } +} diff --git a/top-100-liked/31/31_test.go b/top-100-liked/31/31_test.go new file mode 100644 index 0000000..cb32549 --- /dev/null +++ b/top-100-liked/31/31_test.go @@ -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() +}