二分查找模板

简介: 二分查找模板

原文解释的很好,推荐阅读。二分查找的细节就是while 条件是< 还是 <=,更新right=mid还是mid+1,可以用区间开闭来理解。

while left < right 意味着 搜索区间是 [left,right)左闭右开,

while left <= right 意味着 搜索区间是 [left,right]左闭右闭。

这个搜索空间也决定了后面的更新。以左边界为例,如果使用 left<=right闭区间形式,

初始化left,right = 0,len(nums)-1  对应[0,len(nums)-1]

那么 nums[mid]  > target 时,right = mid-1,搜索区间变为[left,mid-1]

       nums[mid] == target时,right = mid-1,搜索区间为[left,mid-1],继续向左压缩。

       nums[mid] <   target时,left = mid+1,    搜索空间为[mid+1,right]。

而如果使用 left< right 左闭右开形式,初始化left,right = 0,len(nums)  对应[0,len(nums))

nums[mid] >  target 时 ,  right = mid,搜索区间变为[left,mid)

nums[mid] == target时,right = mid,搜索区间为[left,mid),继续向左压缩。

nums[mid] <  target时, left = mid+1,   搜索空间为[mid+1,right)。


给出二分查找模板,包括:二分查找目标值,左边界,右边界。

(Java和Python版本)

直接查找目标值很简单,

nums[mid]<target,压缩左边 left = mid +1

nums[mid]>target,压缩右边 right = mid -1

nums[mid]==target , 返回 mid

查找左边界的前两部分类似,但nums[mid]==target时要继续压缩右边界,锁定左边界,最后返回左边界。注意处理越界情况。

查找右边界同理。

int binary_search(int[] nums, int target) {
    int left = 0, right = nums.length - 1; 
    while(left <= right) {
        int 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;
}
 
int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int 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;
        }
    }
    // 最后要检查 left 越界的情况
    if (left >= nums.length || nums[left] != target)
        return -1;
    return left;
}
 
 
int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int 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;
        }
    }
    // 最后要检查 right 越界的情况
    if (right < 0 || nums[right] != target)
        return -1;
    return right;
}
 
class Solution:
 
    def binary_search(self,nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1
            elif nums[mid] == target:
                return mid
        return -1
 
    def left_bound(self,nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1
            elif nums[mid] == target:
                right = mid -1
        if left >= len(nums) or nums[left] != target:
            return -1
        return left
 
    def right_bound(self,nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1
            elif nums[mid] ==target:
                left = mid + 1
        if right < 0 or nums[right] != target:
            return -1
        return right
相关文章
|
存储 监控 安全
贴片卡的应用场景
贴片卡,通常指的是尺寸小巧、可以直接贴在或嵌入到产品、设备或表面的卡片或芯片,它们集成了电路、存储器、微处理器等电子元件。这些卡片广泛应用于多个行业和领域,以实现数据的存储、传输、认证或控制等功能。以下是贴片卡的一些主要应用场景:
|
10月前
|
JSON Java 程序员
菜鸟之路Day17一一IO流(三)
本文主要介绍了Java中的打印流、压缩/解压缩流以及Commons-io和Hutool工具包的使用。打印流包括字节打印流(PrintStream)和字符打印流(PrintWriter),支持数据原样写出、自动刷新与换行。压缩/解压缩流通过ZipInputStream和ZipOutputStream实现文件和文件夹的压缩与解压。Commons-io和Hutool工具包提供了高效的IO操作方法,简化了文件复制、删除等常见任务。文中还展示了System.out.println()作为打印流的应用示例。
225 2
|
机器学习/深度学习 算法
魔搭案例开源获奖
赵卫东老师在第七届CCF开源创新大赛教学案例赛道中荣获特等奖。他的案例设计注重理论与实践结合,采用阿里魔搭平台和英特尔OpenVINO等先进技术,提升课程的实用性与前瞻性。该案例已开源,并在教学中取得显著成效。赵卫东老师一直坚持“学以致用、产教融合”的理念,多次在教学比赛中获奖。
418 7
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
432 0
|
SQL 安全 Linux
命令执行漏洞
命令执行漏洞
|
安全 Java API
构建基于Spring Boot的REST API安全机制
构建基于Spring Boot的REST API安全机制
Github邮件联系项目源代码作者简单方法
Github邮件联系项目源代码作者简单方法
2341 0
Github邮件联系项目源代码作者简单方法
|
存储 容灾 Linux
中小微企业,软硬一体NAS还是企业文档管理软件?不必再纠结
中小企业选择NAS或企业私有文档管理软件各有优劣。NAS方案易于使用,可快速扩容,适合无专职IT人员的企业,但软硬件绑定紧密,后期扩展受限,价格较高。相比之下,企业文档管理软件不绑定硬件,功能更强大,尤其是权限管理,但需要更多技术知识来配置。考虑成本和灵活性,自建软件NAS或选择功能丰富的专业网盘软件是性价比高的选项,同时,备份和容灾策略不可或缺。
|
消息中间件 Kafka 数据库
实时计算 Flink版操作报错之遇到UnsupportedOperationException异常,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。