mid 最好写成 mid = left + ( right - left ) / 2 以防止溢出
左侧边界
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,a[100005],q;
scanf("%d",&n); //输入数组元素个数
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q); //输入询问次数
while(q--){ //循环q次
int t,l=1,r=n;
scanf("%d",&t);
//核心
while(l<=r){
int mid=l+(r-l)/2;
if(a[mid]>=t) r=mid-1;
else l=mid+1;
}
if(a[l]!=t) l=-1; //若查找的数不存在,输出-1
printf("%d ",l);
}
return 0;
}
lower_bound()
lower_bound ( first , last , val ) 用来查找 [ first , last ) 范围内第一个大于或等于val的元素的位置。如果是数组,返回该位置的指针;如果是容器,返回该位置的迭代器。若查找失败,返回 last 。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,a[100005],q;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
while(q--){
int t;
scanf("%d",&t);
int* i=lower_bound(a+1,a+n+1,t);
if(*i!=t) i=a-1;
printf("%d ",i-a);
}
return 0;
}
右侧边界
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,a[100005],q;
scanf("%d",&n); //输入数组元素个数
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q); //输入询问次数
while(q--){ //循环q次
int t,l=1,r=n;
scanf("%d",&t);
//核心
while(l<=r){
int mid=l+(r-l)/2;
if(a[mid]<=t) l=mid+1;
else r=mid-1;
}
if(a[r]!=t) r=-1; //若查找的数不存在,输出-1
printf("%d ",r);
}
return 0;
}
upper_bound()
upper_bound ( first , last , val ) 用来查找 [ first , last ) 范围内第一个大于val的元素的位置。如果是数组,返回该位置的指针;如果是容器,返回该位置的迭代器。若查找失败,返回 last 。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,a[100005],q;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
while(q--){
int t;
scanf("%d",&t);
int* i=upper_bound(a+1,a+n+1,t);
i--;
if(*i!=t) i=a-1;
printf("%d ",i-a);
}
return 0;
}
二分答案
可以用于解决求最大值最小或最小值最大的问题
应用:防御迷阵、跳石头等
自己总结的一种用法:如果mid可能在查找范围内,可以先让左指针移到mid+1的位置,最后返回 L-1