labuladong_二分查找

零、二分查找框架

复制代码
复制代码
func binarySearch(nums []int, target int) int {
    left := 0
    right := len(nums) - 1 //注意

    for left <= right { //注意
        mid := left + (right-left)/2
        if nums[mid] == target {
            return mid
        } else if nums[mid] < target {
            left = mid + 1 //注意
        } else if nums[mid] > target {
            right = mid - 1 //注意
        }
    }
    return -1
复制代码
复制代码

分析二分查找的一个技巧是:不要出现 else,而是把所有情况用 else if 写清楚,这样可以清楚地展现所有细节。本文都会使用 else if,旨在讲清楚,读者理解后可自行简化。

其中 ... 标记的部分,就是可能出现细节问题的地方,当你见到一个二分查找的代码时,首先注意这几个地方。后文用实例分析这些地方能有什么样的变化。

另外声明一下,计算 mid 时需要防止溢出,代码中 left + (right - left) / 2 就和 (left + right) / 2 的结果相同,但是有效防止了 left 和 right 太大直接相加导致溢出

二、寻找左侧边界的二分搜索

完整代码如下:

复制代码
复制代码
func LeftBound2(nums []int, target int) int {
    left := 0
    right := len(nums) - 1 //注意

    for left <= right { //注意
        mid := left + (right-left)/2
        if nums[mid] == target {
            //收缩右侧边界
            right = mid - 1
        } else if nums[mid] < target {
            //搜索区间变为 [mid+1, right]
            left = mid + 1 //注意
        } else if nums[mid] > target {
            //搜索区间变为 [left, mid-1]
            right = mid - 1
        }
    }
    if left >= len(nums) || nums[left] != target {
        return -1
    }
    return left
}
复制代码
复制代码

这样就和第一种二分搜索算法统一

三、寻找右侧边界的二分查找

类似寻找左侧边界的算法,这里也会提供两种写法,还是先写常见的左闭右开的写法,只有两处和搜索左侧边界不同,已标注:

复制代码
复制代码
func RightBound(nums []int, target int) int {
    left := 0
    right := len(nums) - 1 //注意

    for left <= right { //注意
        mid := left + (right-left)/2
        if nums[mid] == target {
            //收缩左侧边界
            left = mid + 1
        } else if nums[mid] < target {
            //搜索区间变为 [mid+1, right]
            left = mid + 1 //注意
        } else if nums[mid] > target {
            //搜索区间变为 [left, mid-1]
            right = mid - 1
        }
    }
if right < 0 || nums[right] != target {
return -1
}
return right
return right }
复制代码
复制代码

1、为什么这个算法能够找到右侧边界?

答:类似地,关键点还是这里:

        if nums[mid] == target {
            //收缩左侧边界
            left = mid + 1
        }

当 nums[mid] == target 时,不要立即返回,而是增大「搜索区间」的下界 left,使得区间不断向右收缩,达到锁定右侧边界的目的。

当 target 比所有元素都小时,right 会被减到 -1,所以需要在最后防止越界:

 

posted @   卡卡西殿  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示