你真的懂二分吗?

news2024/12/23 14:27:34

二分简述:

二分算法,又称为二分搜索或折半搜索,是一种在有序数组中查找特定元素的搜索算法。其基本思想是将数组分成两半,然后根据目标值与中间元素的大小关系来决定是继续在左侧还是右侧进行搜索。这个过程会不断重复,直到找到目标值或搜索范围为空为止。

下面是二分算法的一般步骤:

1. 初始化:设置两个指针,一个指向数组的起始位置(low),另一个指向数组的结束位置(high)。此时,low = 0,high = 数组长度 - 1或者low = 1,high = 数组长度 。

2. 循环条件:只要low小于等于high,就继续循环。

3. 计算中间位置:在每次循环中,计算中间位置mid=(low + high) / 2。

4. 比较:比较中间元素与目标值。
   - 如果中间元素等于目标值,搜索成功,返回mid。
   - 如果中间元素大于目标值,说明目标值在数组的左侧,更新high为mid - 1。
   - 如果中间元素小于目标值,说明目标值在数组的右侧,更新low为mid + 1。

5. 循环结束:如果low大于high,说明没有找到目标值,搜索失败。

二分算法的时间复杂度是O(log n),其中n是数组的长度。这使得它在大规模数据搜索中非常高效。然而,二分搜索的一个前提条件是数组必须是有序的

二分算法不仅可以用于搜索,还可以用于解决一些优化问题,如找到函数的最大值或最小值等。


二分模板:

在写这篇博客之前看了很多博主的模板,我认为二分的模板只有两种,所有的题都逃不过这两种模板。做过的题为例,100%都属于这两种模板,不是的话,你来找我!

首先贴一个我刚开始学二分时候初步了解,是不完全正确的,但是是最容易理解的一种。

不完全正确的二分:
int quick(int a[],int l,int r,int x){
	int mid;
	while(l<=r){
		mid=(l+r)/2;
		if(x==a[mid]){
			break;
		}else if(x>a[mid]){
			l=mid+1;
		}else if(x<a[mid]){
			r=mid-1;
		}
	}
	return mid;
}

上面这一种可以查找只有唯一一种数的情况,类似1,3,4,5... 这样只有唯一一个的数。像1,1,2,2,2... 这种如果想找到最小的数且靠右边的数,以上模板可能比较难实现。一般题目中都是不是唯一数的情况。这就是我们以下两种模板中的一个。


模板一(查找最右边的):

数组==[1,1,1,1,2,2,2,3...],想要查找最右边的1,就是第四个1,如果用上面的模板,它查到一个1就立马返回了,不管你是哪一个1,取决于你的左右边界了。这样很难实现,那么我们就有下面这一个模板,先来看板子。

while(l<r){
	int mid=l+r+1>>1;
	if(check(mid)){//如果条件成立
		l=mid;
	}else{
		r=mid-1;
	}
}
return l;

 初始l=0,r=len-1。首先判断到任意一个1无论在什么位置,比如说在第二个1,那么check(mid)条件是成立的,我就更新左端点把范围给到右区间,让他去找最右边的1,不断去找... 当判断到最后一个1时,再更新l==r了,此时就退出循环了,也就找到答案了。


模板二(查找最左边的):

还是上面这个数组==[1,1,1,1,2,2,2,3...],如果要查找最左边的一个2,就是第一个2。就可以用下面这个模板。

while(l<r){
	int mid=l+r>>1;
	if(check(mid)){
		r=mid;
	}else{
		l=mid+1;
	}
}
return l;

 初始l=0,r=len-1。首先判断到任意一个2无论在什么位置,比如说在第三个2,那么check(mid)条件是成立的,我就更新右端点把范围给到左区间,让他去找最左边的2,不断去找... 当判断到第一个2时,再更新l==r了,此时就退出循环了,也就找到答案了。


二分底层实现:

在在做题中,二分板子自然很好用,但是还需要写很多代码,以下在特殊情况下可以用upper_bound与lower_bound来代替,这两个函数的底层都是用二分实现的,时间复杂度同样是O(log n),都包含在头文件#include<algorithm>中。

upper_bound:

upper_bound函数是C++ STL中的一个函数,用于在有序序列中查找一个给定的值,并返回第一个大于该值的位置迭代器。

函数原型如下:
upper_bound( first, last, const T& value );

其中,first和last是指定序列的起始和结束迭代器,value是要查找的值。

upper_bound函数会首先在[first, last)区间内进行二分查找,找到第一个大于value的位置,并返回一个指向该位置的迭代器。如果所有元素都小于等于value,则返回last迭代器。

注意,该函数要求序列是有序的,否则结果是未定义的。另外,upper_bound函数使用的是半开区间表示法,即[first, last)表示包含first,但不包含last。

以下是一个使用upper_bound函数查找有序序列中大于某个值的示例:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    vector<int> v = {1, 2, 3, 4, 4, 5, 6, 6, 7, 8};
    int value = 4;
    auto it = upper_bound(v.begin(), v.end(), value);
    if (it != v.end()) {
        cout << "First element greater than " << value << " found at position " << distance(v.begin(), it) << endl;
    } else {
        cout << "No element greater than " << value << " found" << endl;
    }
    
    return 0;
}

输出结果为:
First element greater than 4 found at position 5

这个例子中,有序序列v中第一个大于4的元素是5,upper_bound函数返回的迭代器指向5的位置。


lower_bound:

lower_bound函数是C++ STL中的一个函数,用于在有序序列中查找一个给定的值,并返回第一个大于等于该值的位置迭代器。

函数原型如下:
lower_bound( first, last, const T& value );

其中,first和last是指定序列的起始和结束迭代器,value是要查找的值。

lower_bound函数会首先在[first, last)区间内进行二分查找,找到第一个大于等于value的位置,并返回一个指向该位置的迭代器。如果所有元素都小于value,则返回last迭代器。

注意,该函数要求序列是有序的,否则结果是未定义的。另外,lower_bound函数使用的是半开区间表示法,即[first, last)表示包含first,但不包含last。

以下是一个使用lower_bound函数查找有序序列中大于等于某个值的示例:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    vector<int> v = {1, 2, 3, 4, 4, 5, 6, 6, 7, 8};
    int value = 4;
    
    auto it = lower_bound(v.begin(), v.end(), value);
    if (it != v.end()) {
        cout << "First element greater than or equal to " << value << " found at position " << distance(v.begin(), it) << endl;
    } else {
        cout << "No element greater than or equal to " << value << " found" << endl;
    }
    
    return 0;
}

输出结果为:
First element greater than or equal to 4 found at position 3

这个例子中,有序序列v中第一个大于等于4的元素是4,lower_bound函数返回的迭代器指向4的位置。


题目实践:

洛谷二分题单:

【算法1-6】二分查找与二分答案 - 题单 - 洛谷icon-default.png?t=N7T8https://www.luogu.com.cn/training/111

AcWing题目:

发现更多精彩内容 - AcWing搜索icon-default.png?t=N7T8https://www.acwing.com/file_system/search_engine/web_all/result/index/?search_type=web_entry_problem&search_content=%E4%BA%8C%E5%88%86&source_file_id=0&source_person_id=0

蓝桥杯:

题库 - 蓝桥云课蓝桥云课是国内领先的IT在线编程及在线实训学习平台,专业导师提供精选的实践项目,创新的技术使得学习者无需配置繁琐的本地环境,随时在线流畅使用。以就业为导向, 提供编程、运维、测试、云计算、大数据、数据库等全面的IT技术动手实践环境, 提供Linux、Python、Java、C语言、Node.js、Hadoop、PHP、Docker、Git、 R、SQL、MongoDB、Redis、Swift、Spark等千门热门课程。icon-default.png?t=N7T8https://www.lanqiao.cn/problems/?first_category_id=1&tags=%E4%BA%8C%E5%88%86


由于文章长度,只在此篇博客写几个具有代表性的题。

AcWing 1227. 分巧克力

儿童节那天有 K 位小朋友到小明家做客。

小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。

切出的巧克力需要满足:

  1. 形状是正方形,边长是整数
  2. 大小相同

例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入格式

第一行包含两个整数 N和 K。

以下 N行每行包含两个整数 Hi 和 Wi。

输入保证每位小朋友至少能获得一块 1×1 的巧克力。

输出格式

输出切出的正方形巧克力最大可能的边长。

数据范围

1≤N,K≤10^5,
1≤Hi,Wi≤10^5

输入样例:

2 10
6 5
5 6

输出样例:

2

AC代码:

#include<iostream>
using namespace std;
const int N=1e5+5;
int n,k;
int h[N],w[N];
int maxx;
bool check(int x){
	int sum=0;
	for(int i=0;i<n;i++){
		int l=h[i]/x;
		int r=w[i]/x;
		sum+=l*r;
	}
	return sum>=k?true:false;
}
int main(){
	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>h[i]>>w[i];
		maxx=max(maxx,max(h[i],w[i]));
	}
    //尽可能大,所以第一个模板,因为此题答案唯一,也可以用最初的那个模板
	int l=1,r=maxx;
	while(l<r){
		int mid=l+r+1>>1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
	return 0;
}

洛谷 P2678 [NOIP2015 提高组] 跳石头

AC代码:

#include<iostream>
using namespace std;
const int N=5e4+5;
int num,n,m;
int a[N];
bool check(int x){
	int sum=0,now=0;//sum需要搬走的数量,now上一个相对石块位置
	for(int i=1;i<=n+1;i++){
		if(a[i]-now<x)sum++;//石块距离小于理想的距离,这个石头需要搬
		else now=a[i];//更新对比的石块
	}
	return sum>m?false:true;
}
int main(){
	cin>>num>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	a[n+1]=num;//多加一个终点
    //求最大最短跳跃距离的最大值,第一个模板
	int l=0,r=num;
	while(l<r){
		int mid=l+r+1>>1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
	return 0;
}

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

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

相关文章

YOLOv8改进 | 激活函数 | 十余种常见的激活函数一键替换【完整代码】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

HDU1089、1090、1091、1092、1093、1094、1095、1096、——A+B for Input-Output Practice

目录 HDU1089——AB for Input-Output Practice (I) HDU1090——AB for Input-Output Practice (II) HDU1091——AB for Input-Output Practice (III) HDU1092——AB for Input-Output Practice (IV) HDU1093——AB for Input-Output Practice (V) HDU1094——AB for Inpu…

VSCode上安装C#环境教程

本章教程,教你如何在vscode上,可以快速运行一些基础的c#代码。 1、下载 .NET Code SDK 下载地址:https://dotnet.microsoft.com/zh-cn/download/dotnet/sdk-for-vs-code?utm_source=vs-code&utm_medium=referral&utm_campaign=sdk-install 根据自己的操作系统,选择…

NSSCTF-Web题目27(Nginx漏洞、php伪协议、php解析绕过)

目录 [HNCTF 2022 WEEK2]easy_include 1、题目 2、知识点 3、思路 [NSSRound#8 Basic]MyDoor 4、题目 5、知识点 6、思路 [HNCTF 2022 WEEK2]easy_include 1、题目 2、知识点 nginx日志漏洞执行系统命令 3、思路 打开题目&#xff0c;出现源码 题目要我们上传一个fi…

堆内存申请 - 华为OD统一考试(D卷)

OD统一考试(D卷) 分值: 100分 题解: Java / Python / C++ 题目描述 有一个总空间为100字节的堆,现要从中新申请一块内存,内存分配原则为: 优先分配紧接着前一块已使用的内存,分配空间足够时分配最接近申请大小的空闲内存。 输入描述 第1行是1个整数,表示期望申请的…

星环科技与宁夏银行“大数据联合实验室”揭牌,持续打造金融科技新范式

5月30-31日&#xff0c;2024向星力未来数据技术峰会期间&#xff0c;在峰会现场来宾共同见证下&#xff0c;星环科技与宁夏银行“大数据联合实验室”正式揭牌&#xff0c;宁夏银行股份有限公司首席信息官崔彦刚与星环科技副总裁邱磊共同为联合实验室揭牌。 星环科技与宁夏银行借…

后端开发和你聊聊 JVM 如何优化

作者&#xff1a;京东零售京麦研发 马万全 首先应该明确的是JVM调优不是常规手段&#xff0c;JVM的存在本身就是为了减轻开发对于内存管理的负担&#xff0c;当出现性能问题的时候第一时间考虑的是代码逻辑与设计方案&#xff0c;以及是否达到依赖中间件的瓶颈&#xff0c;最后…

16.1 微信支付

1. 概述 2. 微信支付时序图与流程 官方开发文档 Native支付文档 2.1 Native支付时序图 3. 订单表 单独开发一个支付平台,其他平台遇到支付业务需求时,可调用支付平台完成相应的支付业务 演示:平台有支付平台、商户平台 客户在商户平台发起Vip开通的支付请求,商户平台生成…

IDEA配置Tomcat,解决jsp页面显示问题(Please, configure Web Facet first!)和(There is no configured/running web-se)

在学校&#xff0c;大部分老师还是使用eclipse&#xff0c;他们使用的jsp页面&#xff0c;而我却想使用idea&#xff0c;来操纵jsp页面&#xff0c;可是为什么我将jsp放入项目当中&#xff0c;会出现报错&#xff0c;例如&#xff1a; 又或者&#xff1a; 哎呀&#xff0c;那怎…

数据结构与算法-二分搜索树遍历

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、二分搜…

Halcon 边缘提取(亚像素)

Halcon提供多种边缘提取算法。像素提取方法有常用的边缘提取算子或深度学习分割模型等。考虑到精度问题可能需要提取亚像素边缘。当然也可以提取轮廓&#xff1a;线、圆、椭圆等。本文只讨论提取轮廓。 1 基本概念 正常情况下&#xff0c;无需特殊操作即可提取边缘轮廓。 1…

这些天,有多少人去电影院看巴黎奥运会?

近期&#xff0c;巴黎奥运会的赛况频频登上热搜&#xff0c;中国奥运健儿们的奋勇拼搏令人热血沸腾。而许多观众&#xff0c;或由于租房情况不便于用投影仪观赏比赛&#xff0c;或由于期待更佳的观赛体验&#xff0c;因此有不少人去电影院观赛。由于实时数据的更新性和统计的复…

[Bugku] web-CTF靶场-计算器

计算器 1.开启环境 理论上来说题目最多只能填0-9的答案&#xff0c;如果需要填大于9的需要修改maxlength参数 得出flag

「码」上行动 一物一码+TPM让“多进货多卖货”不再是口号

“门店进货量翻倍&#xff0c;一些门店一个月连续补货3次&#xff01;”在与纷享销客产品经理的电话交流中&#xff0c;X饮品企业的张总难掩喜悦之情。 他兴奋地表示&#xff0c;在北方城市推出的基于一物一码的门店进销双激励码营销试点取得了显著成果&#xff0c;所有参与试…

开放原子校源行 | 武汉大学师生一行走进麒麟信安,开展社会实践交流活动

“开放原子校源行”是开放原子开源基金会作为国家级开源公益平台发起的长期性开源教育推广公益项目。项目拟通过资助高校设立开源社团、推广开源课程、设置开源助学金、引导开源实践等方式培育开源人才&#xff0c;加快将开源文化、理念和技术融入校园&#xff0c;引导广大师生…

CST软件如何实现S-parameter随其他参数变化的1D曲线

本期的FAQ更新一个非常高频的问题&#xff0c;如何实现S-parameter随其他参数变化的1D曲线。有的时候也不一定是S参数&#xff0c;可能是用户关心的阻抗结果&#xff0c;也可能是VSWR等。 在老版本的时候&#xff0c;CST软件有个后处理的宏可以很容易的将某一频点下的0D转换成…

引领未来交通新纪元:综合智慧监管平台

引领未来交通新纪元&#xff1a;综合智慧监管平台 在21世纪的今天&#xff0c;随着科技的飞速发展&#xff0c;交通运输行业作为国民经济的命脉&#xff0c;正经历着前所未有的变革与挑战。面对日益增长的运输需求、复杂多变的交通环境以及公众对安全、高效、绿色出行的迫切期…

AcWingTrie树

字典树的应用背景&#xff1a; 看以下几个题: 1、给出n个单词和m个询问&#xff0c;每次询问一个单词&#xff0c;回答这个单词是否在单词表中出现过 答:简单!map&#xff0c;短小精悍。 好。下一个 每次询问一个前缀&#xff0c;回答询问是多少个单词的前缀。2、给出n个单词和…

硬核!288页Python核心知识笔记(附思维导图,建议收藏)

不少朋友在学习Python时&#xff0c;都会做大量的笔记&#xff0c;随着学习进度的增加&#xff0c;笔记越来越厚&#xff0c;但有效内容反而越来越少。 今天就给大家分享一份288页Python核心知识笔记&#xff0c;相较于部分朋友乱糟糟的笔记&#xff0c;这份笔记更够系统地总结…

软件项目管理工具排行榜:国内外优劣对比

项目管理工具对项目开发的重要性不言而喻&#xff0c;通过对比业内对各个项目管理工具的认可度&#xff0c;筛选出人们公认的软件项目管理工具排行榜&#xff0c;具体详细如下&#xff1a; 1、Microsoft Project 简介&#xff1a;Microsoft Project是一款强大的基于云的项目管理…