二分查找(精确查找、范围搜索)
目录
- 1. 二分查找概述
- 2. 精确查找
- 2.1 【left,right】
- 2. 2 【left,right)
- 3. 范围查找
- 总结
1. 二分查找概述
二分查找法,也称为二分搜索法或折半查找法,是一种在有序数组中查找特定元素的搜索算法。其基本思想是,通过不断将待查找的区间分成两半,并与待查找的元素进行比较,根据比较结果调整查找区间,直到找到元素或区间被缩小至0为止。时间复杂度为O(log n)
- 使用条件:二分查找要求数组必须是有序的,无论是升序还是降序。如果数组无序,则需要先进行排序操作。
- 易错点:while循环过程中,left与right的关系容易错乱;left与right指针的移动容易错。
- 查找情况:二分查找最常见的就是查找某一个序列中存在的精确值target,然而还有一部分是利用二分查找来进行范围划分。
2. 精确查找
为了捋清楚终止条件与指针移动如何确定,需要先从搜索定义区间入手,搜索区间可以分为【left,right】和【left,right)。
2.1 【left,right】
当搜索区间为【left,right】时,说明二分查找过程中,每次搜索区间应该均需要满足该定义。此时二分查找步骤为:
- 确定查找区间:设数组为arr,查找范围为[left, right],初始时left=0,right=n-1,其中n为数组arr的长度。
- 确定循环条件:由于区间是左闭右闭,所以left = right符合定义区间,因此搜索过程中应当满足的条件为while(left <= right)
- 计算中间位置:mid = (left + right) / 2(注意,为了避免整数相加导致的整数溢出问题,有时也使用mid = left + (right - left) / 2的计算方式)。
- 比较中间元素与目标值: 如果arr[mid]等于目标值,则查找成功,返回mid。如果arr[mid]大于目标值,则说明目标值在左半部分,且arr[mid]将不会再需要处于搜索区间内了(因为arr[mid]已经一定不等于target了),则将查找范围更新为[left, mid-1],right = mid - 1。 如果arr[mid]小于目标值,则说明目标值在右半部分,且arr[mid]将不会再需要处于搜索区间内了(因为arr[mid]已经一定不等于target了),将查找范围更新为[mid+1, right],left = mid + 1。
- 重复步骤2和步骤3:直到找到目标值或查找范围为空(即left > right),如果查找范围为空,则说明目标值不存在于数组中。
public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; // 防止溢出,同时更准确地找到中间位置 if (arr[mid] == target) { return mid; // 找到目标元素,返回索引 } else if (arr[mid] < target) { left = mid + 1; // 目标元素在右半部分 } else { right = mid - 1; // 目标元素在左半部分 } } // 未找到目标元素,返回-1 return -1; }
2. 2 【left,right)
当搜索区间为【left,right)时:
- 确定查找区间:设数组为arr,查找范围为[left, right),初始时left=0,right=n,其中n为数组arr的长度。
- 确定循环条件:由于区间是左闭右开,所以left != right符合定义区间,因此搜索过程中应当满足的条件为while(left < right)
- 计算中间位置:mid = (left + right) / 2(注意,为了避免整数除法导致的精度问题,有时也使用mid = left + (right - left) / 2的计算方式)。
- 比较中间元素与目标值: 如果arr[mid]等于目标值,则查找成功,返回mid。如果arr[mid]大于目标值,则说明目标值在左半部分,arr[mid]将不会再需要处于搜索区间内了(因为arr[mid]已经一定不等于target了),并且right一直不在搜索范围内,所以将查找范围更新为[left, mid),right = mid。 如果arr[mid]小于目标值,则说明目标值在右半部分,且arr[mid]将不会再需要处于搜索区间内了(因为arr[mid]已经一定不等于target了),但是left必须在搜索区间内,所以将查找范围更新为[mid+1, right],left = mid + 1。
- 重复步骤2和步骤3:直到找到目标值或查找范围为空(即left >= right),如果查找范围为空,则说明目标值不存在于数组中。
public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length; while (left < right) { int mid = left + (right - left) / 2; // 防止溢出,同时更准确地找到中间位置 if (arr[mid] == target) { return mid; // 找到目标元素,返回索引 } else if (arr[mid] < target) { left = mid + 1; // 目标元素在右半部分 } else { right = mid; // 目标元素在左半部分 } } // 未找到目标元素,返回-1 return -1; }
3. 范围查找
有些时候,target不一定存在于序列中,但是我们想要得到大于target的序列区间,小于等于target的序列区间 或者 大于等于target的序列区间,小于target的序列区间。为了便于讨论,下面将循环条件定义为while(left <= right),指针移动方向为right = mid - 1,left = mid + 1。
由于定义区间为【left,right】,left <= right,搜索到最后left肯定会等于right,此时mid = left = right,下一次移动后将不满足循环条件退出。最后一次是left移动还是right移动?将直接影响最终查找的范围,即等于号归left区间还是right区间。假设代码如下:
while(left <= right){int mid = left + (right - left)/2;if(nums[mid] > target){//这里需要重点考虑,如果有等号存在,则说明如果mid所指就是target,则哪个指针继续跳一个单位,它就必不会等于mid,对应的区间中也就不会出现等于taget的情况//区间【left,n】所指向的值均 >target,区间【0,right】所指向的值均 <= targetright = mid + 1;}else{left = mid - 1;}
}
return left;
可以自行验证,如果target不在序列中,最终left将指向第一个大于target的元素,right将指向最后一个小于target的元素。举例如下:
假设,序列{.....2,3,4,5.......}, target = 3.5,mid = left = right指向4,
此时target小于mid,之后执行right = mid - 1,right指向3,left仍指向4。
nums[【left,n】 ] > target , nums[ 【0,right】 ] < target假设,序列{.....2,3,4,5.......}, target = 4.5,mid = left = right指向4,
此时target大于mid,之后执行left = mid + 1,left指向5,right仍指向4
依然是nums[【left,n】 ] > target , nums[ 【0,right】 ] < target如果target存在于序列中,则最后执行right = mid - 1还是left = mid + 1将会影响target放入哪一个区间中。
如果target存在于序列中,则mid最后所指就是target,所以最后一次移动指针之前,mid = left = right所指向的值就是target,此时哪个指针继续跳一个单位,它就必不会再有机会等于mid等于target,所以其对应的区间中也就不会出现等于taget的情况。
因此上述 if 判断条件中的等号是否存在决定了是right指针会向左移动一格(此时,区间【left,n】所指向的值均 >=target,区间【0,right】所指向的值均 < target),还是left指针向右移动一格(此时,区间【left,n】所指向的值均 >target,区间【0,right】所指向的值均 <= target)
while(left <= right){int mid = left + (right - left)/2;if(nums[mid] >= target){//区间【left,n】所指向的值均 >=target,区间【0,right】所指向的值均 < targetright = mid + 1;}else{left = mid - 1;}
}
return left;
总结
left指向第一个符合if中判断条件的元素,right指向最后一个不符合if中判断条件的元素
- 当判断条件为if(nums[mid] > target)时,最终nums[【left,n】 ] > target , nums[
【0,right】 ] <= target; - 当判断条件为if(nums[mid] >= target)时,最终nums[【left,n】 ] >= target , nums[
【0,right】 ] < target;
这种范围查找也非常适合在遇到元素重复出现,需要找到重复元素的第一个元素或者重复元素的最后一个的位置索引。
相关文章:
二分查找(精确查找、范围搜索)
目录 1. 二分查找概述2. 精确查找2.1 【left,right】2. 2 【left,right) 3. 范围查找总结 1. 二分查找概述 二分查找法,也称为二分搜索法或折半查找法,是一种在有序数组中查找特定元素的搜索算法。其基本思想是&#x…...
软件工程简记
文章目录 一、软件工程要点之软件设计二、UML(Unified Modeling Language,统一建模语言)(一)UML 的整体分类与部分功能(二)UML 各类图的具体内容三、开发模型(一)多种开发模型的特点与问题四、设计模式(一)设计模式的总体概念与原则(二)软件结构设计原则(三)常见…...
【深度学习】【语音TTS】OpenVoice v2,测评,中英文语料,Docker镜像,对比GPT-SoVITS、FishAudio、BertVITS2
https://github.com/myshell-ai/OpenVoice/blob/main/docs/USAGE.md 实际体验OpenVoice v2的TTS效果。 文章目录 环境启动 jupyter代码代码分析主要模块和功能测试一些别的中文和中英文混合总结优点缺点对比GPT-SoVITS、FishAudio、BertVITS2使用我的Docker镜像快速体验OpenVo…...
Kotlin OpenCV 图像图像50 Haar 级联分类器模型
Kotlin OpenCV 图像图像50 Haar 级联分类器模型 1 OpenCV Haar 级联分类器模型2 Kotlin OpenCV Haar 测试代码 1 OpenCV Haar 级联分类器模型 Haar级联分类器是一种用于对象检测(如人脸检测)的机器学习算法。它由Paul Viola和Michael Jones在2001年提出…...
嗖嗖移动业务大厅(Java版)
首先对此项目说明一下,我只完成了项目的基本需求,另外增加了一个用户反馈的功能,但是可能项目中间使用嗖嗖这个功能还有一些需要完善的地方,或者还有一些小bug,就当给大家参考一下了,希望谅解。代码我也上传…...
hcia复习笔记
一、OSI 七层模型 应用层:为应用程序提供服务,如文件传输、电子邮件等。 表示层:数据格式转换、加密解密、压缩解压缩。 会话层:建立、维护和管理会话。 传输层:提供端到端的可靠或不可靠的数据传输服务࿰…...
pycharm中安装、使用扩展工具,以QT Designer为例
pycharm中安装、使用扩展工具,以QT Designer为例 第一步,下载QT Designer安装包。找到QT Designer.exe所在位置,复制路径 第二步,打开Pycharm,选择Setting,找到扩展工具(External Tools…...
【Rust光年纪】Rust语言实用库汇总:从机器翻译到全文搜索引擎
优秀的Rust语言库探索:机器翻译、音频编解码和全文搜索引擎 前言 Rust语言在近年来迅速崛起,成为了一种备受欢迎的系统级编程语言。随着其生态系统的不断丰富,涌现出了许多优秀的库和工具。本文将重点介绍几个用于Rust语言的重要库…...
学习笔记 - 二极管的参数与选型
二极管 普通二极管: 1N4148(高频开关二极管) 整流二极管: 1N4007 1A 1000V1N5408 3A 1000V 肖特基二极管 (白线边为阴极) SS14 SS34 SS54 常见肖特基二极管参数 快恢复二极管 FR107 FR207 FR307 UF4007 可以用快恢复二…...
PMP--冲刺--易混概念
文章目录 十大知识领域一、整合管理项目管理计划与项目文件的区分: 二、范围管理三、进度管理赶工与快速跟进的区分:赶工增加资源,以最小的成本代价来压缩进度工期;快速跟进,将正常情况下按顺序进行的活动或阶段改为至…...
Resolving Maven dependencies
Maven是一种项目管理和构建工具,通常用于Java项目。这个过程包括下载项目所需的所有外部库和插件,并将它们添加到项目的构建路径中。具体来说,它正在处理名为“AAS_byBasyx”的项目或模块的依赖项。这种任务通常在你打开一个新的Maven项目或更…...
【Spring】SSM框架整合Spring和SpringMVC
目录 1.项目结构 2.项目的pom.xml文件 3.spring.xml和springMVC配置文件 4.database.properties和mybatis.xml配置文件 5. 代码编写 6.测试整合结果 1.项目结构 首先创建一个名为ssm_pro的Mavew项目,然后再在主目录和资源目录下,创建如下所示的结…...
优维2024年中思考:大模型赋予新一代运维的“非产品性”启示
近年来,人工智能在各个行业的应用大幅增加,人工智能技术取得重大进步的领域之一是IT运维。 去年四季度,优维科技敏锐地提出“新一代运维核心系统提供商”的战略新定位,决定将“DevOps及运维”回归到“运维”本身,但我…...
【中药网络药理学】筛选细胞衰老和预后相关基因(附分类代码和画图代码)
1、衰老相关基因 从HAGR和msigdb数据获取细胞衰老相关基因,将两者取交集后构建基因蛋白互作网络 HAGR数据库 该库本身提供了下载链接,我在下载后对其进行了清洗 msigdb数据库 以"aging"作为关键词,Search Filters中collection…...
华为的流程体系
缘由 2010年,华为销售额为1850亿元,其中国际市场占65%,净利润238亿元。当时,公司员工达11万人,公司处理合同达5万多个,290万个订单,大量的工作是手工处理,没有统一的流程支持&#…...
算法——长度最小的子数组209 对比代码随想录题解中对于result取值为Integer.MAX_VALUE的思考
具体解题过程可看代码随想录,我主要是对于为什么result也就是子数组和初始化要为Integer.MAX_VALUE有一个疑惑,为什么不是其他值,经过思考后我发现: 情况一:如果result为负数的话是不符合数组长度取值的一个规范的。 情况二&…...
图像处理案例03
HOGSVM数字识别 1 . 步骤2 . 代码 1 . 步骤 读入数据,把数据划分为训练集和测试集用hog提取特征用SVM训练数据测试、评价模型保存模型加载模型,应用模型 2 . 代码 import os import cv2 import sklearn import numpy as np from skimage.feature impo…...
【Kubernetes】k8s集群中kubectl的陈述式资源管理
目录 一.k8s集群资源管理方式分类 1.陈述式资源管理方式 2.声明式资源管理方式 二.陈述式资源管理方法 三.kubectl命令 四.项目生命周期 1.创建 kubectl create命令 2.发布 kubectl expose命令 3.更新 kubectl set 4.回滚 kubectl rollout 5.删除 k…...
串---顺序串实现
顺序串详解 本文档将详细介绍顺序串的基本概念、实现原理及其在 C 语言中的具体应用。通过本指南,读者将了解如何使用顺序串进行各种字符串操作。 1. 什么是顺序串? 顺序串是一种用于存储字符串的数据结构,它使用一组连续的内存空间来保存…...
吴恩达机器学习WEEK2
COURSE1 WEEK2 多维特征 在线性回归中,往往特征不止一个,而是具有多维特征 例如,在预测房价的例子中,我们知道更多的信息: x 1 x_1 x1:房屋的面积 x 2 x_2 x2:卧室的数目 x 3 x_3 x3&a…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...
