技术标签: 算法 c++ 二分 算法合集(c++实现)
二分的数学思想其实就是极限,我们通过取中点的方式,不断地缩小答案所在的区间,让这个区间不断地逼近答案,类似于我们在高数中所学的极限:
我们假设想要寻找上述数轴中的左右边界。
我们先看左边界中的A点,不看B点。我们仔细观察一下A点处符合的性质。
根据上图中的性质,我们就可以开始写二分了。
根据刚刚的描述二分是一个不断逼近地过程,可以理解为两侧端点不断靠近的过程。
将左端点的下标设为 l l l,右端点下标设为 r r r,中间点的下标设为 m i d mid mid, m i d = ( l + r ) / 2 mid = (l+r)/2 mid=(l+r)/2
令 l = 0 l=0 l=0, r = n − 1 r=n-1 r=n−1
如果 m i d mid mid处所对的元素值小于 4 4 4,说明我们的端点 A A A一定不在 m i d mid mid点处,又因为这个序列是单调递增的,所以 m i d mid mid左侧的数字都是小于 m i d mid mid所对的值的。也就是说 m i d mid mid左侧的数字都是小于 4 4 4的,而我们的 A A A处是等于 4 4 4的。
那么知道这个有什么用呢?
这就说明 m i d mid mid的左侧包括 m i d mid mid都不可能是 A A A点,所以我们可以让 l = m i d + 1 l = mid + 1 l=mid+1。
如果 m i d mid mid处所对的值是大于等于 4 4 4的,说明 m i d mid mid右侧的值也一定是大于等于 4 4 4的。
而 m i d mid mid处的值也是等于 4 4 4的,也就是说 m i d mid mid处可能是答案,此时我们考虑一下 m i d mid mid右侧的情况。
如果 m i d mid mid右侧的值都比 m i d mid mid大,那么 m i d mid mid右侧的树也不可能是答案,因为他们都大于 4 4 4。
如果 m i d mid mid右侧还有等于 4 4 4的值,但这些不可能是答案,因为我们找的是区间的左端点,如果 m i d mid mid处是 4 4 4,那么 m i d mid mid右侧的 4 4 4肯定不是左端点。
通过上面对 m i d mid mid右侧的讨论,我们发现 m i d mid mid右侧都不可能是答案,但是 m i d mid mid处有可能是答案。所以我们可以扔掉 m i d mid mid右侧的数,即直接让 r = m i d r = mid r=mid。
通过一轮的比较,我们发现两端的端点再向中间靠拢。
因此我们只需要重复上面的比较,当左端点和右端点合并到一起的时候,那个点就是区间的左端点 A A A。
接着我们考虑区间的右端点。
右端点就是 B B B点,还是和刚才的思路一样,B点一定在这个数轴上,所以我们让左端点 l l l指向起点 0 0 0,右端点 r r r指向最后一个元素下标的 n − 1 n-1 n−1。
我们求出一个中点 m i d mid mid,
如果 m i d mid mid处所对的值是大于4的。
那么 m i d mid mid处肯定不符合条件,由于这个序列是单调递增的,所以 m i d mid mid右侧的数字也一定是大于4的,即不符合条件的。因此,我们可以直接扔掉 m i d mid mid所对的点和它右面的点。即 r = m i d − 1 r = mid - 1 r=mid−1
接着如果 m i d mid mid处所对的值是小于等于4的。
那么 m i d mid mid处有可能是答案,然后我们考虑 m i d mid mid左侧的值。
如果 m i d mid mid左侧的值都是小于4的,那么 m i d mid mid左侧的数字肯定不是答案,可以直接扔掉,如果 m i d mid mid左侧存在等于4的数,这些4也不可能是答案,因为我们找的是右端点,mid在这些4的右面。所以也可以扔掉。
因此如果 m i d mid mid处所对的值,我们可以直接扔掉 m i d mid mid左侧的数,但是需要保留 m i d mid mid,即 l = m i d l=mid l=mid
但是我们找左端点的时候, m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2,而现在由于除法是下取整,所以mid的算法是 ( l + r + 1 ) / 2 (l+r+1)/2 (l+r+1)/2。
为什么呢?
我们看下面这个极端的例子:
我们以下面的题目为例:
上述题目来自acwing网站
#include<iostream>
using namespace std;
const int N=1e6+10;
int arr[N];
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",&arr[i]);
while(m--)
{
//输入要查找的数字
int f=0;
cin>>f;
//开始二分:
//寻找左边界
int l=0,r=n-1;
int mid;
while(l<r)
{
mid=(l+r)>>1;
if(arr[mid]>=f)r=mid;
else l=mid+1;
}
if(arr[l]!=f)cout<<"-1 -1"<<endl;
else
{
cout<<l<<" ";
//寻找右边界
l=0,r=n-1;
while(l<r)
{
mid=(l+r+1)>>1;
if(arr[mid]<=f)l=mid;
else r=mid-1;
}
cout<<r<<endl;
}
}
return 0;
}
假设我们想求一个数字的立方根,并且要保留6位小数,那么必定存在一个范围都是满足这个答案的,因为通过四舍五入后,这个范围的答案都是正确的。此时我们就可以利用浮点数二分。
所以浮点数二分的思想就是,我们让l到r
所组成的区间全部落在答案所在的范围内。此时我们在输出答案即可。
来自acwing。
#include<iostream>
using namespace std;
double x;
double l=-10000.00;
double r=10000.00;
int main()
{
cin>>x;
while(r-l>1e-10)
{
double mid=(r+l)/2;
if(mid*mid*mid>=x)r=mid;
else l=mid;
}
printf("%.6lf",l);;
return 0;
}
#include<stdio.h>
double x;
double l=-10000.00;
double r=10000.00;
int main()
{
scanf("%lf",&x);
while(r-l>1e-10)
{
double mid=(r+l)/2;
if(mid*mid*mid>=x)r=mid;
else l=mid;
}
printf("%.6lf",l);;
return 0;
}
文章浏览阅读5.2k次。使用tortoiseGit工具一直出错,由于没有设置自动获取putty key这一项,从网上找了一个教程,现分享如下,以做参考:前半部分参考网上的例子:http://www.showerlee.com/archives/1300,但会出现“git did not exit cleanly (exit code 128)”错误1.在D盘新建一个目录,例如"D:\Git",并进入目录右键目录空白处选择...
文章浏览阅读1.9k次。发现使用uni-app获取UserInfo,结果使用微信官网栗子发现只弹出提示,没获取到值如下<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">获取用户信息</button>onGotUserInfo: function (e) { console.log(e) ..._component "pages/index/index" does not have a method "getuserinfo" to handle
文章浏览阅读1k次。以太坊空投工具实现代码展示public class AirDropContract { // TODO: 节点URL private final static Web3j web3j = Web3j.build(new HttpService("")); // TODO: 代币合约地址 public static final String coinAddress = ""; // TODO: 部署合约地址 public static final Strin_java nft空投
文章浏览阅读125次。系统可以提供信息显示和相应服务,本系统管理员管理用工单位,派遣员工,合同,黑名单,招聘信息,客户信息,统计员工在职信息与客户开发信息。业务员查看客户开发统计信息,查询供应商与客户。员工可以查询合同,档案,异动以及黑名单信息。开发软件:Eclipse、MyEclipse、IDEA都可以运行。后端:Java+SSM框架。
文章浏览阅读6.1k次,点赞2次,收藏7次。(“#id”).show()表示为display:block;$(“#id”).hide()表示为display:none;$(“#id”).toggle()切换元素的可见状态。如果元素是可见的,切换为隐藏的;如果元素是隐藏的,则切换为可见的。_jquery 隐藏
文章浏览阅读314次。注册表编辑器怎么打开注册表编辑器在电脑运用中使用非常广泛,每个软件的安装都有注册表的生成,所以通过修改注册表还可以设置软件参数等,解决一般电脑软件所无法解决的设置问题。那么注册表编辑器怎么打开呢?很多新手朋友相信都还不知道,下面编辑介绍在windows xp系统下与win 7系统下注册表编辑器怎么打开的方法。windows xp系统下打开注册表编辑器方法方法一:在我的电脑桌面 开始 - 运行 在运..._python如何打开regedit
文章浏览阅读5.7k次,点赞4次,收藏13次。上篇在详解FAT32文件系统中介绍了FAT32文件系统存储数据的原理,这篇就来介绍下NTFS文件系统。NTFS、用过Windows系统的人都知道,它是一个很强大的文件系统,支持的功能很多,存储的原理也很复杂。目前绝大多数Windows用户都是使用NTFS文件系统,它主要以安全性和稳定性而闻名,下面是它的一些主要特点。安全性高:NTFS支持基于文件或目录的ACL,并且支持加密文件系统(E_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储
文章浏览阅读1.2k次。pytorch之常用Loss函数总结参考文档L1、L2、smooth L1 Losssoftmax_cross_entropy_with_logitssparse_softmax_cross_entropy_with_logitsbinary_cross_entropysigmoid_cross_entropy参考文档参考文档参考文档L1、L2、smooth L1 Losssoftmax..._smooth_l1_loss公式
文章浏览阅读462次。1017 A除以B (20 分)本题要求计算 A/B,其中 A 是不超过 1000 位的正整数,B 是 1 位正整数。你需要输出商数 Q 和余数 R,使得 A=B×Q+R 成立。输入格式:输入在一行中依次给出 A 和 B,中间以 1 空格分隔。输出格式:在一行中依次输出 Q 和 R,中间以 1 空格分隔。输入样例:123456789050987654321 7输出样例:17636..._pat 1017乙
文章浏览阅读244次。现在有n种颜色的砖块,第一个必须放第p种颜色,最后一定得放第q种颜色,剩余中间的需要自己构造,使得每相邻两个砖块的颜色不相等,有解随便输出任意一种,无解则输出0。
文章浏览阅读100次。主要是用来存储大量数据的数据库字段,最大可以存储4G字节的非结构化数据。主要介绍字符类型和二进制文件类型LOB数据的存储,单独介绍二进制类型LOB数据的存储。一,Oracle中的LOB数据类型分类1,按存储数据的类型分:①字符类型:CLOB:存储大量 单字节 字符数据。NLOB:存储定宽 多字节 字符数据。②二进制类型:BLOB:存储较大无结构的二进制数据。③二进制文件类型:BFILE:将二进制文..._oracle 多个lob中文件合并
文章浏览阅读1.5k次。Ruby是一种简单快捷的面向对象脚本语言,由日本人松本行弘(Yukihiro Matsumoto)在20世纪90年代开发,遵守GPL协议和Ruby License。它的灵感和特性来自于Perl、Smalltalk、Eiffel、Ada以及Lisp语言。以下是Ruby语言的一些特点:面向对象:在Ruby中,一切皆是对象。这意味着所有的数据和代码都被视为对象,每个对象都有自己的属性和方法。动态类型:Ruby是一种动态类型语言,这意味着你不需要在声明变量时指定其类型。_ruby语言