【二分搜索】二分法及运用

二分搜索

(ps:参考书籍:挑战程序设计)

二分法查找:通过不断缩小解存在的范围,在有序数组中查找特定元素的搜索算法。
经常可见 二分法 与其他算法结合的题目

二分法的思路:

(1)首先,从数组的中间开始搜索,如果该位置的值刚好是目标,则表示找到,结束搜索。

(2)如果第一步的搜索到的值 大于目标,则把数组分成两半,在数组右边区域查找,然后重复步骤(1)的操作。
如果第一步的搜索到的值 小于目标,则把数组分成两半,在数组左边区域查找,然后重复步骤(1)的操作。

(3)如果到数组分成仅剩一个元素还是没找到,就表示查找不到。

朴素的从左到右查找,时间是O(n),二分法查找的时间 O(logn)。

通常写法大致为:

	//二分
	int l=0,r=n;		//	l:左边 r:右边 
	while(l<=r){
		int mid = (l+r)/2;
		if(a[mid]== k){
			cout<<mid;
			break;
		}
		if(a[mid] > k){
			r = mid-1;
		}else{
			l = mid+1;
		}
	}

相关运用

多好时候,我都是写成大概上面那样, L ,R 是数组的起始下标和尾下标。

但是,有些题,由于题目的特性,上面写法做不出来(也可能是我太弱55)
比如下面这道:
在这里插入图片描述
通常的那种写法每次是下标向前移或向后移,是用在求一个数是否在数组里面出现
而这种题是要求实数的,而且数值并没有在数组里面出现。
那怎么办? 应该把L ,R当成是答案的范围,而后用二分求。
写出来大概是这样的:

#include<iostream>
#include<cstdio>
using namespace std;
#include<cmath>
const int maxn = 10005;
int n,k;
double a[maxn];


bool f(double x){
	int cnt=0;
	for(int i=1;i<=n;i++){
		cnt += (int)(a[i]/x); 
	}
	return cnt>=k;
}
int main(){
	cin>>n>>k;
	double len = 0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		len += a[i];
		
	}
	// 二分
	double l =0,r = len;
	for(int i=0;i<100;i++){
		double mid = (l+r)/2;
		if(f(mid)){
			l = mid;
		}else{
			r = mid;
		}
	}
//	cout<<l-1;
	printf("%.2f",l);
	return 0;
}

这种二分,L,R不再是数值的左右标,而是目标答案的左右范围 ,

写法模板:

// 二分
	int l =-1,r = n;
	while(r-l>1)
		int mid = (l+r)/2;
		if(a(mid) >=k){  //如果解满足条件,则解存在的范围变为(l,mid]
			r = mid;
		}else{
			l = mid;	 //如果解不满足条件,则解存在的范围变为(mid,r]
		}
	}
	cout<<r;

最大化最小值 系列问题

类似最大化最小值,最小化最大值,最大化平均值等,通常都用到二分搜索,
比如下面这种, 其他不用怎么说了吧,大致差不多。
在这里插入图片描述

#include<iostream>
#include<cstdio>
using namespace std;
#include<algorithm>
const int maxn = 100005;
int n,m;
int x[maxn];

bool f(int d){
	
	int last = 0;
	for(int i=1;i<m;i++){
		int k=last+1;
		while(x[k] - x[last] <d && k<n){
			k++;
		}
		if(k ==n){
			return false;
		}
		last = k;
	}
	return true;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>x[i];
	}
	sort(x,x+n);
	
	int l=0,r=1e8; 
	while(r-l>1){
		int mid = (l+r)/2;
		if(f(mid)){
			l = mid;
		}else{
			r = mid;
		}
	}
	cout<<l;
	return 0;
} 
发布了75 篇原创文章 · 获赞 1 · 访问量 3629

猜你喜欢

转载自blog.csdn.net/A793488316/article/details/105185602