算法分析与设计 二分查找

article/2025/9/19 12:37:17

算法分析与设计 二分查找

二分查找的基本概念

​ 二分查找是一种在有序数组中查找某一特定元素的查找算法。这种查找方法将查找的时间复杂度从原本的线性时间提升到了对数时间范围,大大缩短了搜索时间。

​ 二分查找的基本思想是:在查找过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则查找过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。

​ 一个基本的二分查找示例如下,在如下数组中找出元素4所在的位置:

在这里插入图片描述

int basicBinarySearch(vector<int> arr, int target){int left = 0;int right = arr.size() - 1;while(left <= right){int mid = left + (right-left)/2;if(target == arr[mid]){return mid;}else if (target < arr[mid]){right = mid - 1; }else if(target > arr[mid]){left = mid + 1;}}return -1;
}

​ 二分查找很简单,但是也有它的难点,其难点就在于在判定条件和边界值的选择上,很容易就会导致越界或者死循环的情况。

​ 对于循环的判定条件,如果查找区间是闭区间[left, right],则判定条件要设为while(left<=right),该判定条件是在出现left > right的情况下终止循环;如果这种闭区间查找区间下使用while(left < right)作为判定条件,该判定条件是在出现left >= right的情况下终止循环,这种情况就没有查找left == right是对应数组位置上的元素,导致错误的查找结果。如果查找区间是闭区间[left, right),则判定条件可以设为while(left < right)

​ 对于边界值,例如有序数组array = [1,2,4,4,4,4,5,6], target = 4,存在目标值有多个的情况,此时我们希望得到上边界目标值的索引,即为 5;或者希望得到下边界目标值的索引,即为 2。这时就不能找到目标值就返回,而是需要继续收紧边界进一步查找边界值。

int lowerBound(vector<int> arr, int target){int left = 0;int right = arr.size();int pos = -1;while(left < right){int mid = left + (right-left)/2;if(target == arr[mid]){pos = mid;right = mid;}else if(target < arr[mid]){right = mid;}else if(target > arr[mid]){left = mid + 1;}}return pos;
}int upperBound(vector<int> arr, int target){int left = 0;int right = arr.size();int pos = -1;while (left < right){int mid = left + (right-left)/2;if(target == arr[mid]){pos = mid;left = mid + 1;}else if(target < arr[mid]){right = mid;}else if(target > arr[mid]){left = mid + 1;}}return pos;
}

二分法求方程的根

​ 求方程 f ( x ) = x 3 − 5 x 2 + 10 x − 80 = 0 f(x) = x^{3} - 5x^{2} + 10x - 80 = 0 f(x)=x35x2+10x80=0 的一个根,若求出的根是 a a a ,则要求 ∣ f ( a ) ∣ < = 1 0 − 6 |f(a)| <= 10^{-6} f(a)<=106

分析问题

​ 对 f ( x ) f(x) f(x) 求导得到, f ′ ( x ) = 3 x 2 − 10 x + 10 f^{'}(x) = 3x^{2} - 10x + 10 f(x)=3x210x+10 。由一元二次方程求根公式知方程 f ′ ( x ) = 0 f^{'}(x) =0 f(x)=0 无解,所以 $f^{’}(x) $ 恒大于 0,可以得出该函数是单调递增的。另外计算可得 f ( 0 ) < 0 , f ( 100 ) > 0 f(0) < 0, f(100) > 0 f(0)<0,f(100)>0 所以在区间 [0,100] 内必然有且只有一个根,又该函数在该区间内是单调递增的,所以可以使用二分法在该区间内寻找方程的根。

double equationRoot(double lower, double upper){double EPS = 1e-6;while(lower <= upper){double root = lower + (upper-lower)/2;double f_root = f(root);if(fabs(f_root) < EPS){return root;}else if(f_root > 0){upper = root;}else if(f_root < 0){lower = root;}}return 0;
}

寻找指定和的整数对

​ 输入 n, ( n<= 100,000) 个整数, 找出其中的两个数,它们之和等于整数 m ( 假定一定有解)。

分析问题

​ 一种简单的思路是使用两重循环,枚举所有的取数方法,但是这种方式的时间复杂度是 O ( n 2 ) O(n^2) O(n2),有没有更高效的算法呢?

​ 可以采用二分法,第一步:将输入的数组排序;第二步:对数组中的每个元素 i使用二分查找在数组中查找值为 m-i 的元素,其时间复杂度为 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

​ 当然本题也可以采用双指针的解法,第一步:将输入的数组排序;第二步:定义两个指针分别指向数组的头部和尾部,然后计算arr[head]+arr[tail]的值,如果该值大于 m,则让tail--,如果小于m,则让head++,直到找出和为m的整数对,双指针查找的时间复杂度为 O ( n ) O(n) O(n)

// 二分查找解法
int integerToBinarySearch(vector<int> arr, int sum, vector<int>& res){sort(arr.begin(),arr.end());vector<int>::const_iterator cit;for(cit = arr.begin(); cit!=arr.end(); ++cit){int target = *cit;int left = 0;int right = arr.size() - 1;while (left <= right){int mid = left + (right-left)/2;if(target == (sum-arr[mid])){res.push_back(target);res.push_back(arr[mid]);return 1;}else if (target > (sum-arr[mid])){right = mid - 1;}else if (target < (sum-arr[mid])){left = mid + 1;}}}return 0;
}// 双指针解法
int integerPairTwoPointer(vector<int> arr, int sum, vector<int>& res){sort(arr.begin(),arr.end());int head = 0;int tail = arr.size()-1;while(head <= tail){if(arr[head]+arr[tail] == sum){res.push_back(arr[head]);res.push_back(arr[tail]);return 1;}else if(arr[head]+arr[tail] < sum){head++;}else if(arr[head]+arr[tail] > sum){tail--;}}return 0;
}

农夫和奶牛问题

​ 农夫 John 建造了一个有 N, (2<=N<=100,000) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是x1,...,xN-1 (0<=xi<=1,000,000,000)。他的 C, (2<=C<=N) 头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,他想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?

分析问题

​ 牛棚的隔间要从第一个开始,我们直接把room设为1,因为第一次判断位置可用的话就是两个房间,后面可用的房间每次增加一,更新坐标是当判断当前房间可用的时候,此时判断下一个房间是否可用,并且更新当前位置,最后跟C比较,看房间是否够用。

​ 抽象为二分查找的方法,第一步:先将隔间的坐标 x1,...,xN-1 排序;第二步在区间 [left, right]内用二分法尝试最大最近距离 D = ( l e f t + r i g h t ) / 2 D = (left + right)/2 D=(left+right)/2 ,left 和 right 的初始值分别为 0 和 1,000,000,000/C。在第二部中如果D可行,则记住该D并在新的区间[left=D+1, right]中继续尝试新的D;如果D不可行,则在新的区间[left, right=D-1]中继续搜索合适的D。

bool isValid(int D, int C) {int room = 1, loc = 0;for (int i=1; i<n; i++) {if (pos[i] - pos[loc] >= D) {room++;loc = i;}}if (room >= C) return true;else return false;
}int FarmerAndCow(vector<int> arr, int C){sort(arr.begin(),arr.end());int left = 1, right = arr.size()-1;while (left <= right) {int mid = left + (left-right)/2;if (isValid(mid)) {left = mid + 1;return mid;} else {right = mid - 1;}}return 0;
}

参考资料

程序设计与算法(二)算法基础

二分查找的写法


http://chatgpt.dhexx.cn/article/V8Nmc7YK.shtml

相关文章

C语言二分查找

我们常常需要对数据进行查找&#xff0c;修改&#xff0c;查找数据有许多方法&#xff0c;我们先看看最简单的顺序查找 int main() {int i, k 0;scanf("%d", &k);int arr[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz sizeof(arr) / sizeof(arr[0]);for (i…

二分查找【详解】

本期介绍&#x1f356; 主要介绍&#xff1a;二分查找的简单思路&#xff0c;为什么必须在有序的前提下才能使用二分查找&#xff0c;该怎么用C程序来实现二分查找&#xff0c;二分查找的局限性&#x1f440;。 目录&#x1f356; 简单思路前提条件编写程序总结 简单思路&…

二分答案

二分答案 总所周知&#xff0c;二分法查找一个数的时间复杂度为O(log n)&#xff0c;所以在int范围内找一个数最多只需要30余次&#xff0c;在longlong范围内最多也只需要60余次。因此&#xff0c;我们可以利用二分这一优势查找答案。即&#xff0c;每次二分后判断该数是不是满…

初探二分算法

又来算法了~~~~ &#x1f603;&#x1f603;&#x1f606;&#x1f606;&#x1f603;&#x1f603;&#x1f603;&#x1f606;&#x1f606;&#x1f606;&#x1f440;&#x1f440;&#x1f606;&#x1f914; 什么是二分算法&#xff1f; 在计算机科学中&#xff0c;二分…

二分(数学背景,边界问题,二分查找,二分答案)

二分法的数学背景 目的 关于二分法的目的&#xff0c;这里引用同济大学数学系出版的《高等数学》第七版上册中关于二分法的相关内容。&#xff08;文段内容多&#xff0c;要有一点耐心~&#xff09; 在科学技术问题中&#xff0c;经常会遇到 求解高次代数方程或其他类型的方程的…

二分模板介绍

以一个典型例题来介绍二分法的两个通用模板&#xff0c;熟练掌握这两个模板可以解决绝大部分二分的问题。 例题&#xff1a;ACWing 789.数的范围 给定一个按照升序排列的长度为n的整数数组&#xff0c;以及q个查询。 对于每个查询&#xff0c;返回一个元素k的起始位置和终止…

二分算法详细解析

二分 有单调性一定可以二分&#xff0c;可以二分不一定有单调性二分的本质是边界不是单调性(单调一定可以二分&#xff0c;不单调的有的也可以二分) 本质&#xff1a;在一个区间上&#xff0c;找到某种性质&#xff0c;每次可以将区间一分为二&#xff08;存在边界&#xff09;…

一篇文章带你搞懂二分

一篇文章教你搞懂二分 二分整数二分实数域上二分二分查找二分答案 二分 到底什么是二分呢&#xff1f;二分二分就是一分为二。简单来说二分就是在有序序列中&#xff0c;通过不断的二分&#xff0c;进而不断地缩小范围去寻找满足我们条件的解。这只是对二分一个狭义上的理解&a…

深入字节版atop: 线上系统的性能监控实践

背景 atop 是一款开源的单机性能监测工具&#xff0c;支持实时观测的同时、也支持读取历史文件排查问题。另外一个优点是除提供 CPU、MEM、DISK 等全局指标外&#xff0c;还提供进程、线程级别的各项指标监控数据。鉴于 atop 的这些优点&#xff0c;字节跳动基于社区的 atop 进…

atop备忘

atop 安装 sudo apt install atop atop 参数说明 监控界面字段说明 ATOP列&#xff1a;该列显示了主机名、信息采样日期和时间点 PRC列&#xff1a;该列显示进程整体运行情况 sys、usr字段分别指示进程在内核态和用户态的运行时间 #proc字段指示进程总数 #zombie字段指示僵…

atop linux,每天学一个 Linux 命令(117):atop

命令简介 atop 命令是一款监控 Linux 系统资源与进程的工具&#xff0c;非内部命令&#xff0c;需要安装。[rootcentos7 ~]# atop -bash: atop: command not found [rootcentos7 ~]# yum install atop -y #Debian && Ubuntu apt-get install atop #Fedora dnf install …

linux 系统性能 检测 命令 atop

atop 主要可以 监测 cpu,内存&#xff0c;硬盘&#xff0c;网络性能&#xff0c;以及 实时读写 日志。 基本用法 1.查看 atop , 实时刷新 按 a ,退出 按q 2.保存日志 atop -w log.txt 3.查看 输出日志 atop -r log.txt &#xff0c; 按 t 查看 下一个样本的性能数据 &a…

Atop使用场景

问题&#xff1a; 1、线上容器环境pod报错无法创建本地线程&#xff0c;如下图所示&#xff1a; 2、日志中出现报错信息 “fork&#xff1a;Cannot allocate memory”。如下图所示&#xff1a; 可能原因 1、内存不够 2、可能是进程数超限导致。系统内部的总进程数达到了 p…

atop工具使用

atop是linux系统下一款监控系统资源与进程的工具。atop以一定的频率记录系统的运行状态,通过它可以了解系统今生前世。atop采集系统资源「cpu、mem、disk、net」的使用情况及所有进程使用系统资源的情况,定期采集相关数据保存日志文件。可以通过atop.daily文件调整数据采集的…

atop安装和使用

atop就是一款用于监控Linux系统资源与进程的工具&#xff0c;它以一定的频率记录系统的运行状态&#xff0c;所采集的数据包含系统资源(CPU、内存、磁盘和网络)使用情况和进程运行情况&#xff0c;并能以日志文件的方式保存在磁盘中。atop是一款开源软件&#xff0c;目前最新版…

linux 之atop 系统监控工具

一、atop介绍 atop是一款用于监控Linux系统资源与进程的工具&#xff0c;它以一定的频率记录系统的运行状态&#xff0c;所采集的数据包含系统资源(CPU、内存、磁盘和网络)使用情况和进程运行情况&#xff0c;并能以日志文件的方式保存在磁盘中&#xff0c;服务器出现问题后&a…

Linux 使用 atop 监控工具

文章目录 应用场景操作步骤安装 atop配置并启动 atop编辑atop配置文件启动atop 分析atop停止atop 应用场景 atop 是一款用于监控 Linux 系统资源与进程的工具&#xff0c;以一定的频率记录系统的运行状态&#xff0c;采集系统资源&#xff08;CPU、内存、磁盘和网络&#xff0…

codeblocks中文包

kdevelop因为python 2.6.2 而不是要求的<2.6的缘故不可以显示出automake。 而删除&#xff12;.6的结果是&#xff11;&#xff13;&#xff12;个包同时要卸载&#xff0c;感觉其中不乏kde桌面的东东&#xff0c;遂放弃&#xff0c;转而投向codeblocks怀抱。 /usr/share/c…

codeblocks使用

原文来源&#xff1a;http://www.cnblogs.com/hackergodness/archive/2011/05/26/2059268.html 原手册下载&#xff1a; http://www.codeblocks.org/docs/manual_en.pdf 译者&#xff1a;JGood(http://blog.csdn.net/Jgood ) 译者言&#xff1a;工欲善其事&#xff0c;必先利其…

CodeBlocks安装及使用

Code::Blocks是一个开放源码的全功能的跨平台C/C集成开发环境&#xff0c;由纯碎的C语言开发完成&#xff0c;使用了著名的图形界面库wxWidgets。由于最近上机指导&#xff0c;学校ACM推荐同学们用的是这款软件&#xff0c;故而对其安装及使用进行一些记录。 一、Code::Blocks…