当前位置: 首页 > news >正文

二分法(Binary Search)

二分法(Binary Search)

一、算法基本原理

1.核心思想

二分法(Binary Search) 是一种基于分治策略的高效 搜索算法,其核心思想是:

  • 利用有序性(单调性)前提
  • 每次搜索区间对半划分
  • 通过比较中间元素与目标值,排除一半不可能的区域。

2.数学原理

假设有序数组长度为n,每次比较后排除一半的元素:

  • 第一次比较后剩余:n/2;
  • 第二次比较后剩余:n/4
  • 第k次比较后剩余:n/2^k

最坏情况需要满足:n/2^k=1
解得:k=log2^n

二、核心算法实现

1.基本二分查找(精准匹配)

#include<vector>#include<iostream>usingnamespacestd;//迭代实现intbinarySearch(vector<int>&nums,inttarget){intleft=0;intright=nums.size()-1;//左闭右闭区间while(left<=right){//区间有效时继续intmid=left+(right-left)/2;//防溢出写法if(nums[mid]==target){returnmid;//找到目标}elseif(nums[mid]<target){left=mid+1;//目标在右半区}else{right=mid-1;//目标在左半区}}return-1;}//递归实现intbinarySearchRecursive(vector<int>&nums,inttarget,intleft,intright){if(left>right){return-1;//基准情况}intmid=left+(right-left)/2;if(nums[mid]==target){returnmid;}elseif(nums[mid]<target){returnbinarySearchRecursive(nums,target,mid+1,right);}else{returnbinarySearchRecursive(nums,target,left,mid-1);}}

2.边界处理技巧

// 三种常用区间写法intbinarySearchStyle1(vector<int>&nums,inttarget){// 风格1:左闭右闭 [left, right]intleft=0,right=nums.size()-1;while(left<=right){// 等号有意义intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;elseif(nums[mid]<target)left=mid+1;elseright=mid-1;}return-1;}intbinarySearchStyle2(vector<int>&nums,inttarget){// 风格2:左闭右开 [left, right)intleft=0,right=nums.size();// 注意right初始值while(left<right){// 等号无意义intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;elseif(nums[mid]<target)left=mid+1;elseright=mid;// 注意这里}return-1;}intbinarySearchStyle3(vector<int>&nums,inttarget){// 风格3:左开右开 (left, right)intleft=-1,right=nums.size();while(left+1<right){// 相邻时停止intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;elseif(nums[mid]<target)left=mid;elseright=mid;}return-1;}

三、二分法模版与变体

1.查找第一个等于target的元素

intfindFirstEqual(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;intresult=-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]>=target){if(nums[mid]==target)result=mid;// 记录但不返回right=mid-1;// 继续向左寻找}else{left=mid+1;}}returnresult;}// 简洁版intfirstEqual(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]>=target){right=mid-1;}else{left=mid+1;}}// 检查边界和值if(left<nums.size()&&nums[left]==target){returnleft;}return-1;}

2.查找最后一个等于target的元素

intfindLastEqual(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;intresult=-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]<=target){if(nums[mid]==target)result=mid;left=mid+1;// 继续向右寻找}else{right=mid-1;}}returnresult;}

3.查找第一个大于等于target的元素

intlowerBound(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]>=target){right=mid-1;// 尝试更小的位置}else{left=mid+1;}}returnleft;// 注意:可能返回nums.size()表示所有元素都小于target}

4.查找第一个大于target的元素

intupperBound(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]>target){right=mid-1;}else{left=mid+1;}}returnleft;}

四、应用场景分类

1.有序数组查找类

// 场景1:在有序数组中查找元素intsearchInSortedArray(vector<int>&nums,inttarget){returnbinarySearch(nums,target);}// 场景2:寻找峰值元素(任意峰值)intfindPeakElement(vector<int>&nums){intleft=0,right=nums.size()-1;while(left<right){intmid=left+(right-left)/2;if(nums[mid]>nums[mid+1]){right=mid;// 峰值在左边或当前}else{left=mid+1;// 峰值在右边}}returnleft;}

2.旋转数组查找类

// 场景3:搜索旋转排序数组(无重复)intsearchInRotatedArray(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;// 判断哪边是有序的if(nums[left]<=nums[mid]){// 左半部分有序if(nums[left]<=target&&target<nums[mid]){right=mid-1;// 目标在有序的左半部分}else{left=mid+1;// 目标在右半部分}}else{// 右半部分有序if(nums[mid]<target&&target<=nums[right]){left=mid+1;// 目标在有序的右半部分}else{right=mid-1;// 目标在左半部分}}}return-1;}

3.二分答案类

// 场景4:求平方根(整数部分)intmySqrt(intx){if(x<=1)returnx;intleft=1,right=x;intresult=0;while(left<=right){intmid=left+(right-left)/2;if(mid<=x/mid){// 防溢出写法result=mid;// 记录可能的答案left=mid+1;// 尝试更大的数}else{right=mid-1;// 平方太大,尝试更小的数}}returnresult;}// 场景5:在D天内送达包裹的能力(最小化最大值问题)intshipWithinDays(vector<int>&weights,intD){// 确定二分边界intleft=*max_element(weights.begin(),weights.end());// 至少能运最重的包裹intright=accumulate(weights.begin(),weights.end(),0);// 一天运完所有while(left<right){intmid=left+(right-left)/2;if(canShip(weights,D,mid)){right=mid;// 能运完,尝试更小的运载能力}else{left=mid+1;// 不能运完,需要更大的运载能力}}returnleft;}boolcanShip(vector<int>&weights,intD,intcapacity){intdays=1;intcurrent=0;for(intweight:weights){if(current+weight>capacity){days++;current=0;if(days>D)returnfalse;}current+=weight;}returntrue;}

4.数学计算类

// 场景6:计算x的n次方根(浮点数二分)doublenthRoot(doublex,intn){if(x==0)return0;doubleleft=0,right=max(1.0,x);doubleeps=1e-12;// 精度要求while(right-left>eps){doublemid=left+(right-left)/2;doublepower=1.0;for(inti=0;i<n;i++){power*=mid;}if(power<x){left=mid;}else{right=mid;}}returnleft;}

五、时间复杂度与空间复杂度

六、总结

二分法是一种高效、优雅的算法,其核心在于:

  1. 有序性前提:数据必须具有某种单调性
  2. 减治思想:每次排除一半不可能的解
  3. 边界维护:正确维护搜索区间的不变式
  4. 模版灵活:根据不同问题调整好判断条件和边界更新
http://www.jsqmd.com/news/575051/

相关文章:

  • 【IDEA插件开发】实战指南系列01 从零构建你的第一个Action插件
  • 如何3分钟搞定Windows苹果驱动:终极免费解决方案
  • OpenClaw本地知识库整合:百川2-13B-4bits模型增强问答准确性
  • Bash脚本并行执行命令的3种实战方法对比(含性能测试)
  • Phi-4-mini-reasoning开源镜像部署:免配置一键启动数学推理服务
  • 解锁Windows全版本安装自由:MediaCreationTool.bat实战指南
  • MRIcroGL:3步掌握开源医学影像3D可视化工具,让诊断更直观
  • 像素风AI终端作品集:Ostrakon-VL-8B在餐饮门店清洁度评估中的实际效果
  • 深度解析MediaCreationTool.bat:Windows部署自动化的架构设计与实现原理
  • 案例5_1:单位数码管显示
  • OpenClaw多终端同步:Qwen2.5-VL-7B任务状态跨设备查看
  • 阿里小云KWS模型多语言支持实战:中英文混合唤醒
  • 5个强力技巧让D3KeyHelper成为你的暗黑3自动化好帮手
  • Java函数计算监控告警体系搭建(Prometheus+OpenTelemetry+自定义TraceID透传),全链路可观测性终极方案
  • KeyarchOS适配seren-0.0.21-1
  • 像素史诗效果展示:支持插入SVG矢量图与交互式图表的研报输出样例
  • Windows Cleaner深度技术解析:Python驱动的系统优化解决方案
  • Phi-4-mini-reasoning惊艳效果:自然语言→一阶逻辑→Z3可验证表达式转换
  • 如何在Linux和Windows上安装配置WPS-Zotero插件:科研工作者的终极解决方案
  • 次元画室与IDE高效联动:在VSCode或IDEA中快速预览生成结果
  • 3步打造智能家居音乐自由:给爱好者的开源方案详解
  • 快速验证openclaw抓取能力:用快马一键生成部署原型
  • 新手福音:在快马平台用ai生成代码轻松学透can协议基础
  • 文墨共鸣使用避坑指南:避免这3个误区让分析更准确
  • 马上深挖!!!三段逆置如何实现数组轮转?!用最简单的话让你秒懂
  • 3个步骤实现Office文档在线预览:解决Web应用中的文件查看难题
  • 新手入门:在快马平台生成代码,理解智能应用控制警告的模拟实现
  • Graphormer多场景教程:学术论文配图生成、课程教学演示、项目原型开发
  • 3步重置JetBrains IDE试用期:开发者必备效率工具指南
  • 三大AI模型实战评测:Grok3、DeepSeek R1、ChatGPT o1在不同场景下的表现差异