因为每个人二分的风格不同,所以在学习二分的时候总是被他们的风格搞晕。有的人二分风格是左闭右开也就是[L,R),有的人是左开右闭的(L,R]。

二分的最基本条件是,二分的序列需要有单调性

下面介绍的时候用v来代表我们二分的目标,用第一个大于v,第一个大于等于v【升序】,最后一个小于v,最后一个小于等于v【降序】来描述,这里可以看到我即将要介绍的4种二分搜索。

1.第一个大于等于v

这就是我们常说的lower_bound()了,这是系统里面自带的库函数,下面是这个函数的原型:

ForwardIterator  lower_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp)

其中first代表左边界迭代器,last代表右边界迭代器(注意左闭右开),val代表你要搜索的值,comp代表排序规则(这个参数在你对非结构体数组二分的时候并不需要,有默认规则)。

实例:

int a[100]={1,2,3,3,4,5,5,6,8,9,22},n;
while(cin>>n){
int p=lower_bound(a,a+11,n)-a;
//如果a是vector,那么lower(a.begin(),a.end(),v)-a.begin();
//你也可以在指定在[L,R)区间内二分lower_bound(a.begin()+L,a.begin()+R,v)-a.begin(),数组也是同理的
cout<<p<<endl;//这里输出的是第一个大于等于n的数的下标
}

接下来我们手写一个lower_bound(),风格为[L,R)。

#include<bits/stdc++.h>
using namespace std;
int main(){
int a[100]={1,2,3,3,4,5,5,6,8,9,22},v;
while(cin>>v){
int L=0,R=11;
while(L<R){
int M=(L+R)/2;
if(a[M]>=v) R=M;
else L=M+1;
}
cout<<L<<endl;
}
return 0;
}

注:1.当a[M]>=v时,由于a[R]是第一个大于等于v的数,那么R最大只能是M

  2.当a[M]<v时,说明[L,M)区间内的数都是小于v的,L作为最后的答案最小只能是M+1

2.第一个大于v

这就是我们常说的upper_bound()了,这是系统里面自带的库函数,下面是这个函数的原型:

ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);

其中first代表左边界迭代器,last代表右边界迭代器(注意左闭右开),val代表你要搜索的值,comp代表排序规则(这个参数在你对非结构体数组二分的时候并不需要,有默认规则)

实例:

int a[100]={1,2,3,3,4,5,5,6,8,9,22},n;
while(cin>>n){
int p=upper_bound(a,a+11,n)-a;
//如果a是vector,那么upper_bound(a.begin(),a.end(),v)-a.begin();
//你也可以在指定在[L,R)区间内二分upper_bound(a.begin()+L,a.begin()+R,v)-a.begin(),数组也是同理的
cout<<p<<endl;//这里输出的是第一个大于等于n的数的下标
}

接下来我们手写一个upper_bound()

#include<bits/stdc++.h>
using namespace std;
int main(){
int a[100]={1,2,3,3,4,5,5,6,8,9,22},v;
while(cin>>v){
int L=0,R=11;
while(L<R){
int M=(L+R)/2;
if(a[M]>v) R=M;
else L=M+1;
}
cout<<L<<endl;
}
return 0;
}

注:1.当a[M]>v时,由于a[R]是第一个大于v的数,那么R最大只能是M

  2.当a[M]<=v时,说明[L,M)区间内的下标都是小于等于v的,L作为最后的答案最小只能是M+1

3.最后一个小于等于v

当数组为降序的,使用lower_bound就是返回第一个小于等于下标,若一开始数组是升续的时候,那么应该先reverse一下,再用lower_bound返回下标p,则在原数组中的下标为n-p-1(假设数组有n个元素)。

这里来介绍一下如何在如果手写一个last_less_equal()。和lower_bound二分区间[L,R)左闭右开不同,last_less_equal()的二分区间为(L,R]右闭左开。

#include<bits/stdc++.h>
using namespace std;
int main(){
int a[100]={1,2,3,3,4,5,5,6,8,9,22},v;
while(cin>>v){
int L=-1,R=10;
while(L<R){
int M=(L+R+1)/2;
if(a[M]<=v) L=M;
else R=M-1;
}
cout<<L<<endl;
}
return 0;
}

注:1.当a[M]<=v时,由于a[L]是最后一个小于等于v的数,那么L最小只能是M。

  2.当a[M]>v时,说明(L,M]区间内的下标都是大于v的,R作为最后的答案最大只能是M-1。

4.最后一个小于v

 上面说过了,当数组为降序的,使用upper_bound就是返回第一个大于下标,若一开始数组是升续的时候,那么应该先reverse一下,再用upper_bound返回下标p,则在原数组中的下标为n-p-1(假设数组有n个元素)。

    这里来介绍一下如何在如果手写一个last_less()。和upper_bound二分区间[L,R)左闭右开不同,last_less_equal()的二分区间为(L,R]右闭左开。

#include<bits/stdc++.h>
using namespace std;
int main(){
int a[100]={1,2,3,3,4,5,5,6,8,9,22},v;
while(cin>>v){
int L=-1,R=10;
while(L<R){
int M=(L+R+1)/2;
if(a[M]<v) L=M;
else R=M-1;
}
cout<<L<<endl;
}
return 0;
}

注:1.当a[M]<n时,由于a[L]是最后一个小于v的数,那么L最小只能是M。

  2.当a[M]>=n时,说明(L,M]区间内的下标都是大于等于v的,R作为最后的答案最大只能是M-1。

我们发现lower_bound()和upper_bound()的M=(L+R)/2,而last_less()和last_less_equal()的M=(L+R+1)/2,(L+R)/2和(L+R+1)/2的区别在于前者是向下取整,后者是向上取整,这和我们定义L或者R是实际的答案有关。

二分搜素——(lower_bound and upper_bound)的更多相关文章

  1. 二分检索函数lower_bound()和upper_bound()

    二分检索函数lower_bound()和upper_bound() 一.说明 头文件:<algorithm> 二分检索函数lower_bound()和upper_bound() lower ...

  2. C++二分查找:lower_bound( )和upper_bound( )

    #include<algorithm>//头文件 //标准形式 lower_bound(int* first,int* last,val); upper_bound(int* first, ...

  3. 二分查找确定lower_bound和upper_bound

    lower_bound当target存在时, 返回它出现的第一个位置,如果不存在,则返回这样一个下标i:在此处插入target后,序列仍然有序. 代码如下: int lower_bound(int* ...

  4. 二分查找(lower_bound和upper_bound)

    转载自:https://www.cnblogs.com/luoxn28/p/5767571.html 1 二分查找 二分查找是一个基础的算法,也是面试中常考的一个知识点.二分查找就是将查找的键和子数组 ...

  5. LeetCode 34 - 在排序数组中查找元素的第一个和最后一个位置 - [二分][lower_bound和upper_bound]

    给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...

  6. STL源码学习----lower_bound和upper_bound算法

    转自:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html 先贴一下自己的二分代码: #include <cstdio&g ...

  7. [STL] lower_bound和upper_bound

    STL中的每个算法都非常精妙, ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一 ...

  8. lower_bound和upper_bound算法

    参考:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html ForwardIter lower_bound(ForwardIte ...

  9. STL源码学习----lower_bound和upper_bound算法[转]

    STL中的每个算法都非常精妙,接下来的几天我想集中学习一下STL中的算法. ForwardIter lower_bound(ForwardIter first, ForwardIter last,co ...

随机推荐

  1. python添加fluent日志记录-aop

    python添加fluent日志,aop实现 1.配置fluent相关信息 fluent_config.ini fluent_config.ini [fluent.aop] #is support f ...

  2. python基础易错题

    1.以下代码输入什么: class Person: a = 1 def __init__(self): pass def getAge(self): print(__name__) p = Perso ...

  3. Luogu 2173 [ZJOI2012]网络 - LCT

    Solution $LCT$ 直接上$QuQ$ 注意$cut$ 完 需要 $d[u + c * N]--$ 再  $link$,  不然会输出Error 1的哦 Code #include<cs ...

  4. 买茶叶想到的哪个比较便宜 x1/y1 >x2/y2 x代表多少钱 y代表 多少克 无聊的试炼

    茶叶1 128元     200克 茶叶2  330元    160克 当然这个哪个便宜 一眼就知道了,这里不过抛砖引玉 128元    330元 200克    160克 我们把价钱用x表示 多少克 ...

  5. Trapping Rain Water LT42

    The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of ...

  6. install virtualenv

    $ [sudo] pip install virtualenv $ mkdir ~/envs $ virtualenv ~/envs/lsbaws/ $ cd ~/envs/lsbaws/ $ ls ...

  7. db2 解锁表

    db2 set integrity for ACT_RU_VARIABLE immediate checked

  8. activiti 清库脚本(转)

    在使用activiti 的时候会经常遇到需要清空数据库中的数据,因此本文重点讲解如何解决该问题. 再删除数据的时候,需要注意有主外键约束的问题?下面罗列的DDL可以结合自身的业务需求进行灵活改造. D ...

  9. 论Java的重要性

    最近,最新的世界编程语言排名最近出炉了,Java位居世界第一.          不仅如此,Java以17.856%超过第二名C语言的8.726%两倍以上,其实,这一现象是十分反常的,因为,在前几年, ...

  10. com/mysql/jdbc/Driver : Unsupported major.minor version 52.0

    解决方案: 1.jdk7+老版5.0驱动com/mysql/jdbc/Driver 2.jdk8+新版6.0驱动com/mysql/cj/jdbc/Driver