二分搜索法的探究与心得

news2025/1/11 19:41:19

引言

在计算机科学中,二分搜索(Binary Search)算法是一种在有序数组中查找特定元素的基本搜索技术。其优点在于高效的搜索速度,时间复杂度为 ( O(log n) ),这一点与时间复杂度为O(n) 的线性搜索法相比,效率提高了数个数量级。二分搜索的核心思想是“分而治之”,即将大问题分解为小问题来逐步解决。

二分搜索适用场景

二分搜索不仅适用于简单的有序数组查找,它也适用于任何可以通过单调性质进行决策的问题,如实数范围内的最优解搜索、概率问题中的阈值确定,以及在计算机图形学中的光线追踪技术等。掌握二分搜索不仅能提升算法效率,也有助于培养分析和解决问题的思维能力。

二分搜索的两种主流写法

传统上,二分搜索有两种流行的写法:左闭右闭 [left, right] 和左闭右开 [left, right)。左闭右闭写法的循环条件为 while (left <= right),而左闭右开写法的循环条件为 while (left < right)。这两种写法虽然在实现上略有不同,但都广泛应用于实践中。

左闭右闭写法

在这种写法中,搜索范围包括 leftright 指向的元素。每次循环将区间分为三部分:小于 mid 的元素、等于 mid 的元素和大于 mid 的元素。根据与 target 的比较结果,我们可以排除其中的一个区间。当 leftright 相遇时,循环结束,此时 leftright 指向相同的可能是 target 的位置。

左闭右开写法

而在左闭右开的写法中,right 指向的元素不包含在搜索范围内。这种方法的结束条件是 leftright 相邻,此时 left 指向的是最后一个不符合条件的元素,right 指向的是第一个符合条件的元素。

left + 1 != right 写法的探讨

这种写法本质上是左闭右开的一种变体。其优势在于处理边界的清晰性和减少了在循环中对 mid 的过度检查。

写法原理

这种写法的基本原理是保持 leftright 指针之间至少有一个元素的间隔。这样,left 永远指向不满足条件的最后一个元素,而 right 指向的是满足条件的第一个元素。当 leftright 相邻时,即 left + 1 == right,它们之间的元素就是我们要找的元素。

二分搜索写法的具体问题优势

left + 1 != right 方法在处理特定类型的问题时显示出其优势,如“查找第一个大于等于目标值的元素”或“查找最后一个小于等于目标值的元素”。在这些问题中,通过维护一个明确的未满足条件和已满足条件的界限,left + 1 != right 写法减少了对边界的额外检查,从而提高了代码的执行效率和可读性。

对边界的处理

使用 left + 1 != right 的方法,边界处理变得直观而简单。在传统的左闭右闭写法中,我们需要小心翼翼地处理 leftright 的更新条件,以避免出现无限循环或者错过目标元素。而在 left + 1 != right 的方法中,我们避免了这种直接更新 leftrightmid 的操作,因此减少了对边界处理的担忧。

对区间的考量

left + 1 != right 的二分搜索中,对区间的考量显得尤为重要。这种写法天然地支持左闭右开的区间操作,即 [left, right)。在每次循环中,我们将区间从 mid 处分割,并根据比较结果决定是将 left 移动到 mid,还是将 right 移动到 mid。由于我们总是保持 leftright 之间至少有一个元素的距离,因此可以确保 mid 永远不会与 leftright 重合,这减少了循环中可能的逻辑错误。

这种方法的一个显著优点是它使得二分搜索的每一步都更加明确。在传统的左闭右闭方法中,当我们找到 mid 满足条件时,我们可能需要额外的逻辑来确定是返回 mid,还是继续在左边或右边的区间中搜索。而在 left + 1 != right 方法中,这种情况得到了简化:我们总是在确信没有遗漏任何可能的元素时才结束循环。

细节解析

1)迭代的过程

 整个二分的过程是一个不断迭代区间的过程,并且 红色游标 指向的元素始终是 红色 的;绿色游标 指向的元素始终是 绿色 的。迭代的过程就是不断向 红绿边界 逼近的过程。

2)结束条件

迭代结束时,红色游标 和 绿色游标 刚好指向 红绿边界,且区间长度为 2。

3)游标初始值

为什么 红色游标 初始值为 −1,绿色游标 初始值为 n ?

  能否将 红色游标 初始化为 0,绿色游标 初始化为 n−1 ? 答案是否定的,试想一下,如果数据元素都是绿色,红色游标 初始化为 0 就违背了 " 红色游标 指向的元素始终是 红色 的 " 这个条件;反之,如果元素都是红色的,也有类似问题。

4)中点位置

5)死循环

上面的程序模板是否会进入死循环?

  我们可以这么来看,当区间为 2 时,循环结束。当区间为 3 时,它一定可以变成区间为 2 的情况,当区间为4时,一定可以变成区间为 2 或者 3 的情况,也就是任何一种情况下,区间一定会减小,并且当等于 2 时,循环结束。所以不会造成死循环。

实践中的应用

在实际应用中,left + 1 != right 的方法尤其适合于寻找区间的极值问题,例如寻找旋转排序数组中的最小元素,或者在一个由两种元素(如“红色”和“绿色”)组成的数组中找到颜色变化的边界。在这些情况下,这种二分搜索方法能够清晰地定位到边界点,而不需要额外的边界检查。

代码模板

public int binarySearch(int[] nums, int target) {
    int left = -1, right = nums.length; // 初始化left为-1,right为数组长度

    while (left + 1 != right) { // 当左右指针相邻时停止
        int mid = left + ((right - left) >> 1); // 计算中点
        if (check()) { 
            left = mid; // 更新左(或右)指针
        } else { 
            right = mid; // 更新左指针
        }
    }
    // 循环结束时,left 为指向第一个绿色元素(或者 right 为指向最后一个红色元素)
    return left;
}

边界情况讨论

在数组的开始和结束位置,left + 1 != right 方法通过简化的逻辑清晰地处理了边界情况。尤其是在数组的结束位置,这种写法自然而然地避免了数组越界的风险,这是因为它始终保持 right 指针在数组范围内。

优势总结

left + 1 != right 的二分搜索法在多个方面展现出它的优势:

  • 精确的边界控制:通过保持 leftright 之间的间隔,这种方法减少了边界值的特殊处理,使得代码更加简洁。
  • 逻辑一致性:更新 leftright 变得一致和直观,不再需要额外的 if 判断来避免包含或排除中点值。
  • 减少错误:由于不需要处理 mid - 1mid + 1,此方法减少了由于错误更新索引而导致的无限循环或漏掉正确元素的风险。
  • 清晰的搜索意图:代码清晰地表达了搜索意图,特别是在区间分割的策略上,这对于阅读和维护代码的人来说是一个巨大的优势。
  • 可扩展性:这种写法易于扩展到更复杂的场景,如多维数组的二分搜索,或者需要进行复杂判断逻辑的问题。

与传统二分的对比

与传统的二分搜索方法相比,left + 1 != right 的写法在概念上更为简单和直观,尤其是对于边界条件的处理。在传统的二分搜索中,如果不小心处理,很容易在边界条件上出现错误,比如忘记了 mid - 1mid + 1,或者在 while 循环的条件中使用了错误的比较运算符。而在 left + 1 != right 的方法中,这些问题都不复存在。我们可以用一种更加一致和安全的方式来处理搜索逻辑。

结论

left + 1 != right 的二分搜索方法以其简洁的边界处理和清晰的逻辑流程,提供了一种新颖而有效的解决问题的方法。它不仅加强了对二分搜索的理解,还扩展了这一算法的应用范围,使得开发者能够更容易地实现和维护相关的算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1444398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cad基础学习

基础操作与设置 切换工作空间 调整鼠标 界面右击&#xff0c;选项 选项中找到显示&#xff0c;十字光标调到最大 当然也可以输入命令op,回车。它会自动打开这个界面 画一个直线 上面选直接&#xff0c;单击俩个点&#xff0c;画出一个直线。然后空格收尾&#xff0c;这就画出…

Python API的使用简述

文章目录 Web APIGit 和 GitHub使用 API 调用请求数据安装 requests处理响应 API处理响应字典监视API的速率限制使用 Pygal 可视化仓库改进Pygal图表添加自定义工具提示 本篇文章&#xff1a;我们叙述如何编写一个独立的程序&#xff0c;并对其获取的数据进行可视化。这个程序将…

文件上传总结:用原生解决前端文件上传操作(单个,多个,大文件切片)

目录 第一章 前言 第二章 理解文件上传的对象 2.1 如何利用原生实现 2.2 认识理解文件上传的四个对象 2.2.1 file对象 2.2.2 blob对象 2.2.3 formData对象 2.2.4 fileReader对象 2.2.4.1 了解fileReader对象基本属性 2.2.4.2 了解 fileReader对象基本方法 2.2.4.3…

[office] Excel2019函数MAXIFS怎么使用?Excel2019函数MAXIFS使用教程 #知识分享#微信#经验分享

Excel2019函数MAXIFS怎么使用&#xff1f;Excel2019函数MAXIFS使用教程 Excel2019函数MAXIFS怎么使用&#xff1f;这篇文章主要介绍了Excel2019函数MAXIFS使用教程,需要的朋友可以参考下 在今年&#xff0c;Excel除了新版本Excel2019&#xff0c;其中有一个新功能MAXIFS函数&am…

知识价值2-什么是IDE?新手用哪个IDE比较好?

IDE是集成开发环境&#xff08;Integrated Development Environment&#xff09;的缩写&#xff0c;是一种软件应用程序&#xff0c;旨在提供集成的工具集&#xff0c;以方便开发人员进行软件开发。IDE通常包括代码编辑器、编译器、调试器和其他工具&#xff0c;以支持软件开发…

使用耳机壳UV树脂制作一个耳机壳需要多长时间?

使用耳机壳UV树脂制作一个耳机壳所需的时间取决于多个因素&#xff0c;包括工艺流程、加工方式、设备和技术水平等。一般来说&#xff0c;制作一个耳机壳需要数小时到数天不等。 以下是影响制作时间的几个主要因素&#xff1a; 获取耳模时间&#xff1a;获取耳模的时间取决于…

最适合新手的SpringBoot+SSM项目《苍穹外卖》实战—(一)项目概述

黑马程序员最新Java项目实战《苍穹外卖》&#xff0c;最适合新手的SpringBootSSM的企业级Java项目实战。 项目简介 《苍穹外卖》项目的定位是一款为餐饮企业&#xff08;餐厅、饭店&#xff09;定制的软件产品。该项目是一个在线外卖订购系统&#xff0c;顾客可以通过网站或者…

RabbitMQ的延迟队列实现[死信队列](笔记一)

关于死信队列的使用场景不再强调&#xff0c;只针对服务端配置 注意&#xff1a; 本文只针对实现死信队列的rabbitMQ基本配置步骤进行阐述和实现 目录 1、docker-compose 安装rabbitMq2、查看对应的版本及插件下载3、安装插件和检测 1、docker-compose 安装rabbitMq a、使用d…

错误的集合(力扣刷题)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 由于作者比较菜&#xff0c;还没学malloc这个函数&#xff0c;因此这个题目只写一些与原题大致的思路。 题目链接&#xff1a;645. 错误的集合 - 力扣…

任务管理软件的实用价值及优选推荐:提升工作效率的利器

任务管理软件是一种用于组织任务、将任务分配给个人并监控其进展的软件。该软件可以帮助确保任务在预算内按时完成。它在协同工作环境中特别有用&#xff0c;在这种环境中多人在处理需要跟踪和监视的任务。无论是初创公司、中小型企业还是大型组织&#xff0c;都可以从任务管理…

【书生·浦语大模型实战营】学习笔记1

大模型成为发展通用人工智能的重要途经 专用模型&#xff1a;针对特定任务&#xff0c;一个模型解决一个问题 通用大模型&#xff1a;一个模型应对多种任务、多种模态 书生浦语大模型系列 上海人工智能实验室 轻量级、中量级、重量级 7B 和 123B的轻量级和中量级大模型都是开源…

统计数字出现次数的数位动态规划解法-数位统计DP

在处理数字问题时,我们经常遇到需要统计一定范围内各个数字出现次数的情况。这类问题虽然看起来简单,但当数字范围较大时,直接遍历统计的方法就变得不再高效。本文将介绍一种利用数位动态规划(DP)的方法来解决这一问题,具体来说,是统计两个整数a和b之间(包含a和b)所有…

【开源】JAVA+Vue.js实现车险自助理赔系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 车辆档案模块2.4 车辆理赔模块2.5 理赔照片模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 车辆表3.2.3 理赔表3.2.4 理赔照片表 四、系统展示五、核心代码5.1 查询车…

杨辉三角的变形(数学)

题目 import java.util.Scanner;public class Main {public static void main(String[] args) { // 1 // 1 1 1 // 1 2 3 2 1 // 1 3 6 7 6 3 1 // 1 4 10 16 19 16 10 4 1Scanner sc new Scanner(System.in);int n sc.nextInt();int[][] res new int[n1][2*n];for(i…

《统计学简易速速上手小册》第3章:概率分布与抽样技术(2024 最新版)

文章目录 3.1 重要的概率分布3.1.1 基础知识3.1.2 主要案例&#xff1a;顾客到访分析3.1.3 拓展案例 1&#xff1a;产品缺陷率分析3.1.4 拓展案例 2&#xff1a;日销售额预测 3.2 抽样方法与推断3.2.1 基础知识3.2.2 主要案例&#xff1a;顾客满意度调查3.2.2 拓展案例 1&#…

Java项目:19 基于SpringBoot的医院管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 医院管理系统 分为三个角色 管理员、医生、病人 管理员的主要功能&#xff1a;系统管理、医生管理、患者管理、预约管理、病史管理、住院信息管理、管…

C++ | string类按位赋值小技巧

一切的起因是string类的谜之初始化。 在写代码的时候&#xff0c;我发现即使没有用字符串初始化string对象&#xff0c;也可以对string对象进行下标操作&#xff0c;就像这样&#xff1a; #include<iostream> #include<string> using namespace std; int main() {…

【Go】一、Go语言基本语法与常用方法容器

GO基础 Go语言是由Google于2006年开源的静态语言 1972&#xff1a;&#xff08;C语言&#xff09; — 1983&#xff08;C&#xff09;—1991&#xff08;python&#xff09;—1995&#xff08;java、PHP、js&#xff09;—2005&#xff08;amd双核技术 web端新技术飞速发展&…

探索Spring Validation:优雅实现后端数据验证的艺术

在现代Web应用开发中&#xff0c;数据验证是一项至关重要的任务&#xff0c;确保应用程序接收到的用户输入符合预期规范&#xff0c;不仅能够提高系统的健壮性&#xff0c;也能有效防止潜在的安全漏洞。Spring Framework通过其内置的Spring Validation模块&#xff0c;为我们提…