解法一:寻找左侧边界的二分查找
当目标元素 target 不存在数组 nums 中时,搜索左侧边界的二分查找的返回值可以做以下几种解读:
1、返回的这个值是 nums 中元素值大于等于 target 的最小索引。
2、返回的这个值是 target 应该插入在 nums 中的索引位置。
3、返回的这个值是 nums 中小于 target 的元素个数。
参考:二分查找框架
func searchInsert(nums []int, target int) int {
if len(nums) == 0{
return -1
}
left, right := 0, len(nums)-1
for left <= right{ // 搜索区间为 [left, right]
mid := left + (right - left)/2
if nums[mid] == target {
right = mid -1 // 收缩右侧边界
}else if nums[mid] < target{
left = mid + 1 // 搜索区间变为 [mid+1, right]
}else {
right = mid -1 // 搜索区间变为 [left, mid-1]
}
}
return left
}
参考
根据逻辑将「搜索区间」全都统一成了两端都闭,便于记忆,只要修改两处即可变化出三种写法
func binarySearch(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right - left) / 2
if nums[mid] < target {
left = mid + 1
} else if nums[mid] > target {
right = mid - 1
} else if nums[mid] == target {
// 直接返回
return mid
}
}
// 直接返回
return -1
}
func leftBound(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right - left) / 2
if nums[mid] < target {
left = mid + 1
} else if nums[mid] > target {
right = mid - 1
} else if nums[mid] == target {
// 收缩右侧边界
right = mid - 1
}
}
// 判断 target 是否存在于 nums 中
// 如果越界,target肯定不存在
// 其实if 中 left < 0 这个判断可以省略,因为对于这个算法,left 不可能小于 0
// left 初始化就是 0,且只可能一直往右走,那么只可能在右侧越界
// 养成代码习惯,在访问数组索引之前保证索引在左右两端都不越界
if left < 0 || left >= len(nums) {
return -1
}
// 判断一下 nums[left] 是不是 target
if nums[left] == target {
return left
}
return -1
}
func rightBound(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right - left) / 2
if nums[mid] < target {
left = mid + 1
} else if nums[mid] > target {
right = mid - 1
} else if nums[mid] == target {
// 收缩左侧边界
left = mid + 1
}
}
if right < 0 || right >= len(nums) {
return -1
}
if nums[right] == target {
return right
}
return -1
}