C++中的二分

二分是算法中比较基础简单的,但是边界值问题是二分问题比较头疼的

如果处理不好很容易会越界,或者死循环。

二分查找一个确定值(不考虑相同值的左右边界)

本二分查找采用搜索左闭右开的区间数组,所以 [l,r) = [l,r-1];

如果从下标1开始记录第一个数,那查找区间 [1,n+1] r=n(实际长度)+1 

或者[1,num.size],size包括了arr[0]的个数了 num.size=n+1

如果从下标0开始记录第一个数,那查找区间为 [0,n] 因为 arr[0]也记录也一个数,arr[n]没有记录

或者[0,num.size] 

	int l=1,r=num.size();
	int mid;
    int flag=1;
	while(l<r){
		 mid=(l+r)/2;
		if(num[mid] == x)
		{
            flag=0;
			break;
		}
		else if(num[mid] > x)
		{
			r=mid;
		}
		else if(num[mid] < x)
		{
			l=mid+1;
		}
	}
    if(flag)
    {
        cout<<"0";
    }
    else
    {
        cout<<num[mid];
    }

或者

int bina(int l ,int r,int x)
{
	int mid;
	while(l<r){
		mid=(l+r)/2;
		if(num[mid] == x)
		{
			return mid;
		}
		else if(num[mid] > x)
		{
			r=mid;
		}
		else if(num[mid] < x)
		{
			l=mid+1;
		}
	}
    retuen -1;
}

二分查找相同元素的边界值(左边界或者右边界)

如vector<int> num = {0,2,4,7,7,7,8,12,15,17,19,20,23,25};

需要查找最左边或者右边的7

查找相同元素的左边界值

	int l=0,r=num.size();
    int mid;
	while(l<r){
		mid=(l+r)/2;
		//cout<<l<<" "<<r<<" "<<mid<<endl;
		if(num[mid] == x)
		{
			r=mid;//如果找到相等值,向左收缩继续,将mid变成右边界开区间
		}
		else if(num[mid] > x)
		{
			r=mid;
		}
		else if(num[mid] < x)
		{
			l=mid+1;
		}
	}
	cout<<l<<" "<<num[l]<<endl;

查找相同元素的右边界值

		int l=1,r=num.size();
        int mid;
		while(l<r){
			 mid=(l+r)/2;
			 //cout<<l<<" "<<r<<" "<<mid<<endl;
			 cout<<l<<" "<<r<<" "<<mid<<endl;
			if(num[mid] == x)
			{
				l=mid+1;//如果找到相等值,向右收缩继续,右边界值不变,左边界值(l+1,r]
			}
			else if(num[mid] > x)
			{
				r=mid;
			}
			else if(num[mid] < x)
			{
				l=mid+1;
			}
		}
	    cout<<l-1<<" "<<num[l-1]<<endl;

查找右边界的时候。一定要注意,目标值为l-1,因为r一直大于目标值

如果找不到目标值,就默认返回比 目标值 第一个大的元素

c++<algorithm>中二分算法

lower_bound :

lower_bound(begin,end,目标值) ,从begin到end-1位置,二分查找等于目标值的下标,如果没有找到,就返回第一个比目标值大的元素,获取下标应在减去num,

int k = lower_bound(num,num+k,x) - num

upper_bound:

upper_bound(begin,end,目标值),从begin到end-1位置,二分查找第一个大于目标值的下标

注意:使用vector时,应该用迭代器,

auto it =upper_bound(num.begin(),num.end(),x)-num.begin()

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

vector<int> num = {0,2,4,7,7,7,8,12,15,17,19,20,23,25};
             //      1 2 3 4 5 6  7  8 9  10 11 12 13
int numm[] = {0,2,7,7,7,8,9,10,12,12,15,16};
           // 0 1 2 3 4 5 6  7  8  9 10 11

int main()
{
	
	int x;
	cin>>x;
	int i = lower_bound(numm,numm+12,x)-numm;
	cout<<i<<" "<<numm[i]<<endl;
	auto pos=upper_bound(num.begin(),num.end(),x)-num.begin();
	cout<<num[pos];

}

按从大到小排序返回第一个小于目标值的 下标
 int pos=lower_bound(num,num+n,查找值,greater<int>())-num;  //返回数组中第一个小于或等于被查数的值 
 iint pos=upper_bound(num,num+n,查找,greater<int>())-num;  //返回数组中第一个小于被查数的值 

二分查找例题

Problem - 1742E - Codeforces

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值