二分搜素——(lower_bound and upper_bound)
因为每个人二分的风格不同,所以在学习二分的时候总是被他们的风格搞晕。有的人二分风格是左闭右开也就是[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)的更多相关文章
- 二分检索函数lower_bound()和upper_bound()
二分检索函数lower_bound()和upper_bound() 一.说明 头文件:<algorithm> 二分检索函数lower_bound()和upper_bound() lower ...
- C++二分查找:lower_bound( )和upper_bound( )
#include<algorithm>//头文件 //标准形式 lower_bound(int* first,int* last,val); upper_bound(int* first, ...
- 二分查找确定lower_bound和upper_bound
lower_bound当target存在时, 返回它出现的第一个位置,如果不存在,则返回这样一个下标i:在此处插入target后,序列仍然有序. 代码如下: int lower_bound(int* ...
- 二分查找(lower_bound和upper_bound)
转载自:https://www.cnblogs.com/luoxn28/p/5767571.html 1 二分查找 二分查找是一个基础的算法,也是面试中常考的一个知识点.二分查找就是将查找的键和子数组 ...
- LeetCode 34 - 在排序数组中查找元素的第一个和最后一个位置 - [二分][lower_bound和upper_bound]
给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...
- STL源码学习----lower_bound和upper_bound算法
转自:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html 先贴一下自己的二分代码: #include <cstdio&g ...
- [STL] lower_bound和upper_bound
STL中的每个算法都非常精妙, ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一 ...
- lower_bound和upper_bound算法
参考:http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html ForwardIter lower_bound(ForwardIte ...
- STL源码学习----lower_bound和upper_bound算法[转]
STL中的每个算法都非常精妙,接下来的几天我想集中学习一下STL中的算法. ForwardIter lower_bound(ForwardIter first, ForwardIter last,co ...
随机推荐
- oracle 异常错误处理
分类: Oracle 5.1 异常处理概念 5.1.1 预定义的异常处理 5.1.2 非预定义的异常处理 5.1.3 用户自定义的异常处理 5.1.4 用户定义的异常处理 5.2 异常错误传播 5.2 ...
- HTML JavaScript语法练习
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- tableView上出现空白的解决办法
创建tableView后,出现如下效果 解决办法: self.automaticallyAdjustsScrollViewInsets = NO; 个人认为,应该是取消系统默认行为,保证界 ...
- POJ 3469.Dual Core CPU 最大流dinic算法模板
Dual Core CPU Time Limit: 15000MS Memory Limit: 131072K Total Submissions: 24830 Accepted: 10756 ...
- 用户态处理arp、ndisc neighbour solication 报文
问题背景: 想要协议栈给不是接口ip的报文,ipv4回复arp request,ipv6回复 ndisc solication. #include <stdio.h> //调用该函数成为一 ...
- NOIP2017提高组day2T1题解(奶酪)
题目链接:奶酪 这道题还是很水的,在下拿了满分. 并没有用什么高级的算法,我讲一下基本思路. 我们把每个洞都视为一个节点. 我们读入相关数据后,就先进行预处理,通过每个节点的信息和题目的规定,建立一张 ...
- 20155312 2016-2017-2 《Java程序设计》第九周学习总结
20155312 2016-2017-2 <Java程序设计>第九周学习总结 课堂内容总结 两个类有公用的东西放在父类里. 面向对象的三要素 封装 继承 多态:用父类声明引用,子类生成对象 ...
- 20155312 张竞予 2006-2007-2 《Java程序设计》第四周学习总结
20155312 2006-2007-2 <Java程序设计>第四周学习总结 课堂笔记 Ctrl+shift+T调出三个窗口,分别是"vi编写代码","jav ...
- Syslog和Windows事件日志收集
Syslog和Windows事件日志收集 EventLog Analyzer从分布式Windows设备收集事件日志,或从分布式Linux和UNIX设备.交换机和路由器(Cisco)收集syslog.事 ...
- php 超时设置笔记
php.ini default_socket_timeout=5 mysql.connect_timeout = 5 max_execution_time = 5 php-fpm pm = dynam ...