二分模板(整数二分和小数二分)

我们以下讨论都是对于有序数组
整数二分确实比较难搞哈,我也是学了两边才差不多懂了y总的思路,写题的时候按照需求套模板就好了。

对于整数二分,我们可将其按照我们要找的数字x分为两段。

整数二分

1. x是红色区间的右端点,将[L,R]分为[L,M-1]和[M,R]

//这个是思路1
while(L<R){
	M=(L+R+1)/2;
	if(M是红色)   L=mid;
	else         R=mid-1;
}
//这个是模板1
while(L<R){
	M=(L+R+1)/2;//注意这里如果不上取整的话,当区间只有两个数字的时候可能会陷入死循环
	if(que[M]<=x)  L=mid;
	else           R=mid-1;
}//最后找到的que[L]是小于等于x的第一个数字

2. x是绿色区间的左端点,将[L,R]分为[L,M]和[M+1,R]

//这个是思路2
while(L<R){
	M=(L+R)/2;
	if(M是绿色)   R=mid;
	else         R=mid+1;
}
//这个是模板2
while(L<R){
	M=(L+R)/2;
	if(que[M]>=x)  R=mid;
	else          L=mid+1;
}//最后找到的que[R]是大于等于x的第一个数字

写该类题目先判断我们想要的数字是什么类的。

比如这个计蒜客的题

在这里插入图片描述

Sample Input

3
2 5 8
2
10
5

Sample Output

8
5

这个题的思路就是我想找到 大于等于 这个要查询的数字的第一个下标(也就是绿色区域的左端点)。
也就是说判断条件的是if(que[mid]>=x),注意这个括号里就是我们根据自己的需求填写的,这里要找大于等于x的第一个数字就是这个判断条件。对应代码如下:
while(L<R){
	mid=(L+R)/2;
	if(que[mid]>=x)	R=mid;//注意这里是R=mid,上面更新mid的时候不用加一
	else            L=mid+1;
同样也可以寻找小于等于x的第一个下标if(que[mid]<=x),对应代码如下:
while(L<R){
	mid=(L+R+1)/2;
	if(que[mid]<=x)	L=mid;//注意这里是L=mid,上面更新mid的时候需要加一,否则陷入死循环
	else            R=mid-1;

我的解题代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int que[N];
int main(){
	int n,m,x;
	cin>>n;
	for(int i=0;i<n;i++)
	cin>>que[i];
	cin>>m;
	while(m--){
		cin>>x;
		int left=0;
		int right=n-1;
		while(left<right){
			int mid=(left+right) >> 1;//因为这里是right=left所以是下取整 
			if(que[mid]>=x) {
				right=mid;
			}
			else{
				left=mid+1;
			}
		}//此时que[right]是大于等于x的第一个数 
		if(que[right]==x) cout<<que[right]<<endl;//说明数组中存在x 
		else {//说明此时que[right]是大于x的第一个数,那我们就要判断它和它左边的数字谁更接近x了 
			int iend;
			if(right!=0)//判断right是不是数组边界,否则会出错 
			iend= abs(que[right]-x) < abs(que[right-1]-x) ? que[right]:que[right-1]; 
			else 
			iend=que[right];
			cout<<iend<<endl;
		}
	}
	return 0;
}

相信自己!多写几个题就明白了。

先确定你要的数字是 ## 大于x ## 大于等于x ## 小于x ## 小于等于x

对应的if中判断条件分别为 ## que[mid]>x ## que[mid]>=x ## que[mid]<x ## que[mid]<=x

根据不同的if条件,我们写出对应的处理和else语句,if后面跟的直接就是需要更新的边界=mid;对应else后面才是mid-1或+1,然后再根据是否为right=mid,是的话mid的更新中不需要加1。得到的数字一定是满足这个if语句的第一个位置下标。

这样写可以避开所有的坑!

小数二分

while(r-l<1e-8){//在一个极小的区间 
	double mid=(l+r)/2;
	if(mid>=x) r=mid;//这里我有点存疑,两个浮点数这么比较合理吗 
	else l=mid; 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值