开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
二分模板
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用: ->求绿色分界点
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
/*返回结果时应根据是否查找成功来返回不同的结果
若查找成功, 则返回 l,若查找失败, 则返回 -1
-1 定义为查找失败时应返回的值, 根据题目的不同而不同
if (check(l)) return l; // 查找成功
return -1; // 查找失败
*/
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:->求红色分界点
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = (l + r + 1) >> 1; //注意:需要+1
if (check(mid)) l = mid;
else r = mid - 1;
}
/*返回结果时应根据是否查找成功来返回不同的结果
若查找成功, 则返回 l,若查找失败, 则返回 -1
-1 定义为查找失败时应返回的值, 根据题目的不同而不同
if (check(l)) return l; // 查找成功
return -1; // 查找失败
*/
return l;
}
注意: 在一个区间内,我们每次都要选择答案所在那个区间进行处理 ;每次我们把整个区间的长度缩小一半,选择一个答案所在的区间 ,每次都能保证区间里面是有答案的
在一个区间内部去二分一下边界 ,每次在选择答案所在的区间的时候,每次都能保证区间是一定有答案的 ,题目可能无解,二分一定有解
题目:数的范围
相当于是找到>=x的最左边的位置和<=x的最右边的位置
#include<iostream>
using namespace std;
const int N = 100010;
int n,m;
int q[N];
int main()
{
scanf("%d %d",&n,&m);
for(int i = 0;i<n;i++) scanf("%d",&q[i]);
while(m--) //m次查询
{
int x = 0;
scanf("%d",&x);
int left = 0,right = n-1;
//1.找>=x最左边的位置
while(left < right)
{
int mid = left+right>>1;
if(q[mid] >= x) right = mid;
else left = mid+1;
}
if(q[left] != x) //可能没有x这个值
{
cout <<"-1 -1"<<endl;
}
else //有x这个值
{
cout << left <<" ";//打印找>=x最左边的位置
//2.找<=x最右边的位置
int left = 0,right = n-1;
while(left<right)
{
int mid = left+right+1>>1;
if(q[mid]<=x) left = mid;
else right = mid-1;
}
//因为上面是else今来的,所以肯定有x这个值
//可以直接打印<=x最右边的位置
cout << left<<endl;
}
}
return 0;
}