深入二分思想

深入二分思想

二分在实际使用中常常会出现死循环的问题

这是因为我们对二分临界状态的不熟悉而导致的,这里介绍一种通用的分界想法:

整数二分:

int l = begin - 1, r = end + 1;
while (l + 1 != r) {
int mid = l + r >> 1;
if (judge(mid)) l = mid;
else r = mid;
}

规定当 l + 1 == r 时,退出二分查找,因为在对整数区间进行二分时,最终状态的 lr 是紧密相邻的

judge 函数同样需要进行设计:

1 2 3 4 4 4 5 6

针对以上序列,我们如果想查找:(下标从1开始)

<4 <=4 >4 >=4

的元素下标,那么我们二分的 judge 和 返回的值就不同:

//查找 <4 <=4 时:
bool judge(int x){
if (arr[x] < 4) return 1;
return 0;
}
//最终状态的边界线处在3和4之间(下标)
//二分最后的l就是3,r就是4(下标)

这样的judge函数,我们可以查找出 <<= 的位置

同样的:

//查找 >4 >=4 时:
bool judge(int x){
if (arr[x] <= 4) return 1;
return 0;
}
//最终状态的边界线处在6和7之间(下标)
//二分最后的l就是6,r就是7(下标)

这样的judge函数,我们可以查找出 >>= 的位置


在上述的judge函数中,我们不难写出lr 的位置关系,但是为什么只用在judge中,添加一个=就能改变查找的方向呢?

还是以这段序列为例:

1 2 3 4 4 4 5 6

查找 <<=时,我们目标是把边界线定位在34之间

if (arr[x] < 4) return 1;//(l=mid)
else return 0;//(r=mid)

因此,当我们的arr[mid]==4时,我们就要将右边界移动到mid

反之:

查找 >>=时,我们目标是把边界线定位在45之间

if (arr[x] < 4) return 1;//(l=mid)
else return 0;//(r=mid)

因此,当我们的arr[mid]==4时,我们就要将左边界移动到mid


也可以使用stl库内的 upper_bound()lower_bound()函数进行二分查找

需要提前对查找的序列进行有序化处理

用法如下:x为需要查找的元素

//对于静态数组
upper_bound(arr+begin,arr+len,x)
lower_bound(arr+begin,arr+len,x)
//对于stl容器
upper_bound(arr.begin(),arr.end(),x)
lower_bound(arr.begin(),arr.end(),x)

其中,在对静态数组进行查找时,arr+begin为从第几个元素开始查找,len为需要查找的区间长度,arr+len则表示查找到第几个元素停止

upper_bound()返回的是第一个 大于 x迭代器lower_bound()返回的是第一个 大于等于 x迭代器

对于同样的序列:arr[]={1 2 3 4 4 4 5 6 }

upper_bound(arr, arr+8, 4);
lower_bound(arr, arr+8, 4);
//通过*解引用处理
cout << *upper_bound(arr, arr + 8, 4) <<' ' << *lower_bound(arr, arr + 8, 4);
//输出的结果为 5 4

注意upper_bound()lower_bound()返回的是迭代器,可以通过 - 操作计算他们的绝对距离(大于0),就是等于4的元素的个数

posted @   才瓯  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示