二分查找总结——模板与运用

二分查找

时间复杂度log(n),基本上随便用
可以用来找数,查答案…

记得待查找序列一定是有序的

模板:

bool search(int l,int r,ll tar){		//查找一个数是否存在 
	while(l<=r){
		int mid=(l+r)>>1;
		if(arr[mid]==tar){
			return 1;
		}else if(arr[mid]>tar){
			r=mid-1;
		}else{
			l=mid+1;
		}
	}
	return 0;
}

double版本的要注意控制精度

double searchf(double l,double r,double tar){
	while(r-l<eps){
		double mid=(l+r)/2;
		if(mid==tar){
			return tar;
		}else if(mid>tar){
			r=mid;
		}else{
			l=mid;
		}
	}
	return mid;
}

当然也可以用函数库的

lower_bound( begin,end,num)//返回第一个大于或等于num的数字
upper_bound(begin,end,num);	//返回第一个大于num的数字
binary_search(begin,end,num);

内部用的也是二分思想,节省时间

其他用法:

因为二分时间复杂度很低,在1e9内可以说是常数级别,甚至可以直接套在暴力里面
out of sort(暴力查询每一个数,是否符合二分查找的结果)(生动形象)

所以当有些题目的答案落在单调区间上,并且答案很容易出来时,可以直接查找答案区间,检查mid值是否满足条件
一般这类题要求的是最小区间的最大值(反正就是反着来) ,难点在于思维与构建check函数

例如这个进击的奶牛 (勇敢牛牛,不怕困难)

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); 
using namespace std;
typedef long long ll;
const ll N =  1e9+50000;
const double eps = 1e-6;
const double pi=3.1415926;
const int INF =1<<30;

int arr[100006];
int a,b,c;

bool check(int x){							//检查 
	int cep=0;								//不能住的隔间 
	int l=1;
	for(int i=2;i<=a;i++){					//遍历所有隔间 
		while(i<=a&&arr[i]-arr[l]<x){		//不满足距离 
			i++;
			cep++;
			if(a-cep<b){					//隔间数不够 
				return 0;
			}
		}
		l=i;
	}
	return 1;
}

int main(){
	ios
	cin>>a>>b;
	for(int i=1;i<=a;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+1+a); 	//记得先排序 
	int l=1,r=1e9+5;
	int mid,sum=0;
	//用二分查找答案区间,直到得到最优解 
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid)){
			l=mid+1;
			sum=mid;	//不断更新sum的值 
		}else{
			r=mid-1;
		}
	}
	cout<<sum<<"\n";
	return 0;
}

小青蛙过河
The Frog’s Games
同样是查找答案

int arr[500009]; 
int brr[500009];
int l,m,n;
bool check(ll x){		//看看x最短跳跃距离下能否过河
	int sum=0;
	int cnt=1;
	int steps=0;
	while(sum<l){
		int cep=0;
		for(int i=cnt;i<=n+1;i++){
			cep+=brr[i];
			if(cep>x){
				cep-=brr[i];	//过不去就退回一步 
				steps++;		//记录步数 
				cnt=i;
				break;
			}
		}
		sum+=cep;
		if(sum==l){
			steps++;
		}
		if(steps>m){			//步数超了,到不了对岸 
			return 0;
		}
	}
	return 1;
} 

int main(){
	while(cin>>l>>n>>m){
		for(int i=1;i<=n;i++){
			scanf("%d",&arr[i]);
		}
		sort(arr+1,arr+n+1);
		arr[0]=0;
		arr[n+1]=l;						//注意最后一个石头就是河对岸,即河的长度 
		int max=0;
		for(int i=1;i<=n+1;i++){
			brr[i]=arr[i]-arr[i-1];		//每个石头间距离 
			if(brr[i]>max){
				max=brr[i];
			}
		}
		ll le=max;
		ll r=1e9;
		ll ans=0;
		while(le<=r){					//过程和上面那个题一样 
			ll mid=(r+le)>>1;
			if(check(mid)){
				r=mid-1;
				ans=mid;
			}else{
				le=mid+1;
			}
		}
		cout<<ans<<"\n";
	}
	return 0;
}

短短二分,花样还不少,有些题根本想不到是二分,还是得多刷题 orz

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值