diff --git a/codes/go/chapter_dynamic_programming/coin_change_ii.go b/codes/go/chapter_dynamic_programming/coin_change_ii.go index b4bccd50e..4dd587709 100644 --- a/codes/go/chapter_dynamic_programming/coin_change_ii.go +++ b/codes/go/chapter_dynamic_programming/coin_change_ii.go @@ -23,7 +23,7 @@ func coinChangeIIDP(coins []int, amt int) int { // 若超过背包容量,则不选硬币 i dp[i][a] = dp[i-1][a] } else { - // 不选和选硬币 i 这两种方案的较小值 + // 不选和选硬币 i 这两种方案之和 dp[i][a] = dp[i-1][a] + dp[i][a-coins[i-1]] } } diff --git a/codes/go/chapter_searching/binary_search_edge.go b/codes/go/chapter_searching/binary_search_edge.go new file mode 100644 index 000000000..0639ef606 --- /dev/null +++ b/codes/go/chapter_searching/binary_search_edge.go @@ -0,0 +1,31 @@ +// File: binary_search_edge.go +// Created Time: 2023-08-23 +// Author: Reanon (793584285@qq.com) + +package chapter_searching + +// 二分查找最左一个 target +func binarySearchLeftEdge(nums []int, target int) int { + // 等价于查找 target 的插入点 + i := binarySearchInsertion(nums, target) + // 未找到 target ,返回 -1 + if i == len(nums) || nums[i] != target { + return -1 + } + // 找到 target ,返回索引 i + return i +} + +// 二分查找最右一个 target +func binarySearchRightEdge(nums []int, target int) int { + // 转化为查找最左一个 target + 1 + i := binarySearchInsertion(nums, target+1) + // j 指向最右一个 target ,i 指向首个大于 target 的元素 + j := i - 1 + // 未找到 target ,返回 -1 + if j == -1 || nums[j] != target { + return -1 + } + // 找到 target ,返回索引 j + return j +} diff --git a/codes/go/chapter_searching/binary_search_insertion.go b/codes/go/chapter_searching/binary_search_insertion.go new file mode 100644 index 000000000..99ab2b50d --- /dev/null +++ b/codes/go/chapter_searching/binary_search_insertion.go @@ -0,0 +1,49 @@ +// File: binary_search_insertion.go +// Created Time: 2023-08-23 +// Author: Reanon (793584285@qq.com) + +package chapter_searching + +// 二分查找插入点(无重复元素) +func binarySearchInsertionSimple(nums []int, target int) int { + // 初始化双闭区间 [0, n-1] + i, j := 0, len(nums)-1 + for i <= j { + // 计算中点索引 m + m := i + (j-i)/2 + if nums[m] < target { + // target 在区间 [m+1, j] 中 + i = m + 1 + } else if nums[m] > target { + // target 在区间 [i, m-1] 中 + j = m - 1 + } else { + // 找到 target ,返回插入点 m + return m + } + } + // 未找到 target ,返回插入点 i + return i +} + +// 二分查找插入点(存在重复元素) +func binarySearchInsertion(nums []int, target int) int { + // 初始化双闭区间 [0, n-1] + i, j := 0, len(nums)-1 + for i <= j { + // 计算中点索引 m + m := i + (j-i)/2 + if nums[m] < target { + // target 在区间 [m+1, j] 中 + i = m + 1 + } else if nums[m] > target { + // target 在区间 [i, m-1] 中 + j = m - 1 + } else { + // 首个小于 target 的元素在区间 [i, m-1] 中 + j = m - 1 + } + } + // 返回插入点 i + return i +} diff --git a/codes/go/chapter_searching/binary_search_test.go b/codes/go/chapter_searching/binary_search_test.go index 0b6084d68..eee9d3eb2 100644 --- a/codes/go/chapter_searching/binary_search_test.go +++ b/codes/go/chapter_searching/binary_search_test.go @@ -22,3 +22,40 @@ func TestBinarySearch(t *testing.T) { t.Errorf("目标元素 6 的索引 = %d, 应该为 %d", actual, expected) } } + +func TestBinarySearchEdge(t *testing.T) { + // 包含重复元素的数组 + nums := []int{1, 3, 6, 8, 12, 15, 23, 26, 31, 35} + fmt.Println("\n数组 nums = ", nums) + + // 二分查找左边界和右边界 + for _, target := range []int{6, 7} { + index := binarySearchLeftEdge(nums, target) + fmt.Println("最左一个元素", target, "的索引为", index) + + index = binarySearchRightEdge(nums, target) + fmt.Println("最右一个元素", target, "的索引为", index) + } +} + +func TestBinarySearchInsertion(t *testing.T) { + // 无重复元素的数组 + nums := []int{1, 3, 6, 8, 12, 15, 23, 26, 31, 35} + fmt.Println("数组 nums =", nums) + + // 二分查找插入点 + for _, target := range []int{6, 9} { + index := binarySearchInsertionSimple(nums, target) + fmt.Println("元素", target, "的插入点的索引为", index) + } + + // 包含重复元素的数组 + nums = []int{1, 3, 6, 6, 6, 6, 6, 10, 12, 15} + fmt.Println("\n数组 nums =", nums) + + // 二分查找插入点 + for _, target := range []int{2, 6, 20} { + index := binarySearchInsertion(nums, target) + fmt.Println("元素", target, "的插入点的索引为", index) + } +}