LeetCode35 搜索插入位置(二分查找)

68 阅读2分钟

leetcode.cn/problems/se…

image.png

解法一:寻找左侧边界的二分查找

当目标元素 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
}

参考

labuladong.online/algo/essent…