整数二分、小数二分、三分、二分函数整理

二分

二分的类型有整数二分、小数二分、三分、二分函数

整数二分

二分查找可以查找一个数的出现的位置或者一个数在哪个区域出现,这里的难点是区域重复数字

二分查找需要的条件:用于查找的内容逻辑上来说是需要有序的,查找的数量只能是一个,而不是多个

有两种形式的二分查找,分别是左闭右闭[left, right]和左闭右开[left, right)

查找一个准确的数字或者判断一些线性递增的数据对应在哪里

//左闭右闭
int search(int nums[], int size, int target) //nums是数组,size是数组的大小,target是需要查找的值
{
    int left = 0;
    int right = size - 1;	// 定义了target在左闭右闭的区间内,[left, right]
    while (left <= right) {	//当left == right时,区间[left, right]仍然有效
        int middle = left + ((right - left) / 2);//等同于 (left + right) / 2,防止溢出
        if (nums[middle] > target) {
            right = middle - 1;	//target在左区间,所以[left, middle - 1]
        } else if (nums[middle] < target) {
            left = middle + 1;	//target在右区间,所以[middle + 1, right]
        } else {	//既不在左边,也不在右边,那就是找到答案了
            return middle;
        }
    }
    //没有找到目标值
    return -1;
}
//左闭右开
int search(int nums[], int size, int target)
{
	int left = 0;
	int right = size; //定义target在左闭右开的区间里,即[left, right)
	while (left < right) {	//因为left = right的时候,在[left, right)区间上无意义
		int middle = left + ((right - left) / 2);
		if (nums[middle] > target) {
			right = middle; //target 在左区间,在[left, middle)中 
		} else if (nums[middle] < target) {
			left = middle + 1;
		} else {
			return middle;
		}
	} 
    // 没找到就返回-1
	return -1;
}
洛谷 P2249 【深基13.1】查找
//有重复数字取最左边
#include<bits/stdc++.h>
using namespace std;

const int N=1e6+10;
int number,times,a[N],findnum;

int main()
{
	cin>>number>>times;
	for(int i=0;i<number;i++)
	{
		cin>>a[i];
	} 
	while(times--)
	{
		cin>>findnum;
		int left=0,right=number,mid;//左闭右开 
		while(left<right)
		{
			mid=left+right>>1;
			if(findnum>a[mid]) left=mid+1;
			else right=mid;
		}
		if(a[left]==findnum) cout<<left+1<<" ";
		else cout<<"-1 ";
	}
	return 0; 
} 
洛谷 P2249 【深基13.1】查找
//有重复数字取最左边
#include<bits/stdc++.h>
using namespace std;

const int N=1e6+10;
int number,times,a[N],findnum;

int main()
{
	cin>>number>>times;
	for(int i=0;i<number;i++)
	{
		cin>>a[i];
	} 
	while(times--)
	{
		cin>>findnum;
		int left=0,right=number-1,mid;//左闭右闭
		while(left<=right)
		{
			mid=left+right>>1;
			if(findnum>a[mid]) left=mid+1;
			else right=mid-1;
		}
		if(a[left]==findnum) cout<<left+1<<" ";//在left和right相等的时候,正好取到那一位时,right会-1,所以最后left的位置是解的位置
		else cout<<"-1 ";
	}
	return 0; 
} 

查找一个数字在其中对应的左值/右值,注意分析临界条件和哪个区间的做法一样跟随等于号,分析区间在两个端点中间的情况,根据题意判断两种方法最后的输出

洛谷 P1873 [COCI 2011/2012 #5] EKO / 砍树
#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
int tree[N],M,number;

bool judge(int height);

int main()
{
	cin>>number>>M;
	int maxn=0;
	for(int i=0;i<number;i++)
	{
		cin>>tree[i];
		if(maxn<tree[i]) maxn=tree[i];
	}
	//cout<<maxn;
	int left=0,right=maxn,mid;
	while(left<right)//左闭右开
	{
		mid=left+right>>1;
		//cout<<mid<<endl;
		if(judge(mid))
		{
			//cout<<judge(mid);
			left=mid+1;
		}
		else right=mid;
	}
	cout<<left-1;//这里的减一分析是正常的二分查找步骤后,区域的二分查找最后一定有两个端点,按照前闭后开的二分写法会left、right全取到右边,题目意思是左边,所以left-1
	return 0;
}

bool judge(int height)
{
	int ans=0;
	for(int i=0;i<number;i++)
	{
		if(tree[i]>height)
		{
			ans+=tree[i]-height;
		}
		if(M<=ans) return true;//这里的小于等于号是经过分析,发现正好等于要和刚好多一点放在一个区间中
	}
	return false;
}
洛谷 P1873 [COCI 2011/2012 #5] EKO / 砍树
#include<bits/stdc++.h>
using namespace std;

const int N=1e6;
int tree[N],M,number;

bool judge(int height);

int main()
{
	cin>>number>>M;
	int maxn=0;
	for(int i=0;i<number;i++)
	{
		cin>>tree[i];
		if(maxn<tree[i]) maxn=tree[i];
	}
	//cout<<maxn;
	int left=0,right=maxn,mid;
	while(left<=right)//左闭右闭
	{
		mid=left+right>>1;
		if(judge(mid)) left=mid+1;
		else right=mid-1;
	}
	cout<<right;
	return 0;
}

bool judge(int height)
{
	int ans=0;
	for(int i=0;i<number;i++)
	{
		if(tree[i]>height)
		{
			ans+=tree[i]-height;
		}
		if(M<=ans) return true;
	}
	return false;
}

小数二分

小数二分指的是输出结果是小数的二分查找,不需要像整数二分一样考虑边界问题,设置精度阈值即可

洛谷 P1024 [NOIP2001 提高组] 一元三次方程求解
#include<bits/stdc++.h>
using namespace std;

float a,b,c,d;

float muti(float tx);

int main()
{
	cin>>a>>b>>c>>d;
	for(float x=-100;x<100;x++)
	{
		if(muti(x)*muti(x+1)>0) continue;
		else if(muti(x)*muti(x+1)<0)
		{
			float lt=x,rt=x+1,mid;
			while(rt-lt>=0.0001)//设置精度阈值
			{
				mid=(lt+rt)/2;
				if(muti(lt)*muti(mid)<0) rt=mid;
				else lt=mid;
			}
			printf("%.2f ",lt);
		}
		else if(muti(x)==0)
		{
			printf("%.2f ",x);
		}
	}
	return 0;
}

float muti(float tx)
{
	return a*tx*tx*tx+b*tx*tx+c*tx+d;
}

三分

三分用在求曲线的极大值和极小值的时候

洛谷 P1883 【模板】三分 | 函数
#include<bits/stdc++.h>
using namespace std;

//图像题先画图一定要先把题目条件看完再画图像,出图像之后可能看得出隐含条件 
const int N=1e4+10;
int T,n,a[N][3];
double divide[N],esp=1e-11;//要经过数学分析题目条件得到精度

double muti(double tx); 

int main()
{
	cin>>T;
	while(T--)
	{
		memset(divide,0,sizeof(divide));
		memset(a,0,sizeof(a));
		cin>>n;
		for(int i=0;i<n;i++)
		{
			cin>>a[i][0]>>a[i][1]>>a[i][2];
		}
		double lt=0,rt=1000,mid1,mid2;
		while(rt-lt>=esp)
		{
			mid1=(lt*2+rt)/3;//	三分
			mid2=(lt+rt*2)/3;
			if(muti(mid2)>muti(mid1))
			{
				rt=mid2;
			}
			else lt=mid1;
		}
		printf("%.4lf\n",muti(lt));
	}
}

double muti(double tx)
{
	double maxn=-1e9;
	for(int i=0;i<n;i++)
	{
		maxn=max(maxn,a[i][0]*tx*tx+a[i][1]*tx+a[i][2]);
	}
	return maxn;
}

二分函数

binary_search二分查找,只能返回一个值是否在一个排列好的数组或结构体中出现过

binary_search(a,a+number,3,less<int>());//这里的参数是起始地址、终止地址、寻找的量、排序的方式
binary_search(a,a+number,4,greater<double>());//在函数里,less/greater指第一个数字

lower_bound二分查找,找到第一个大于等于一个数的位置

/*在数组a中从a[begin]开始到a[end - 1]按照cmp函数来比较进行二分查找第一个大于等于k的数的位置
如果有第一个大于等于k的数则返回该数的地址,否则k太大的情况返回a[end]的地址*/
lower_bound(a,a+number,3,less<int>());
lower_bound(a,a+number,4,greater<double>());

upper_bound二分查找,找到第一个大于一个数的位置

/*在数组a中从a[begin]开始到a[end - 1]按照cmp函数来比较进行二分查找第一个大于k的数的位置
如果有第一个大于k的数则返回该数的地址,否则k太大的情况返回a[end]的地址*/
upper_bound(a,a+number,3,less<int>());
upper_bound(a,a+number,4,greater<double>());
洛谷 P2249 【深基13.1】查找
#include<bits/stdc++.h>
using namespace std;

const int N=1e6+10;
int number,a[N],times;

int main()
{
	cin>>number>>times;
	for(int i=0;i<number;i++)
	{
		cin>>a[i];
	}
	int tempnum;
	int* tempi;
	for(int i=0;i<times;i++)
	{
		cin>>tempnum;
		tempi=lower_bound(a,a+number,tempnum,less<int>());//这里直接减去a就能变成索引 
		//cout<<a+number<<" "<<tempi<<endl;
		if(!binary_search(a,a+number,tempnum,less<int>())) cout<<"-1 ";
		else cout<<tempi-a+1<<" ";
	}
	return 0;
}
洛谷 P1102 A-B 数对
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+10;
int n,c,a[N];

int main()
{
	cin>>n>>c;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	long long ans=0;//注意分析每一种数据的阈值,数据分析
	sort(a,a+n,less<int>());
	for(int i=0;i<n;i++)
	{
		ans+=upper_bound(a,a+n,a[i]-c,less<int>())-lower_bound(a,a+n,a[i]-c,less<int>());
	}
	cout<<ans;
	return 0;
}
  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值