二分法(算法竞赛进阶指南笔记)

本文详细介绍了二分查找算法,包括整数二分、实数域上的二分、三分法求单峰函数极值以及如何将二分应用于求解问题。通过实例解析了二分查找在单调序列中的应用,讨论了不同情况下的二分模板选择,并展示了如何将二分转化为判定问题,以解决实际竞赛中的复杂问题。此外,还提到了精度控制和无解情况的处理策略。

二分(算法竞赛进阶指南笔记)

作用:

①二分的基础用法是在单调序列或单调函数中进行查找.

②当问题的答案具有单调性时,就可以通过二分把求解转化为判定(根据复杂度理论,判定的难度小于求解)。

③还可以扩展到通过三分法去解决单峰函数的极值以及相关问题。

一、整数二分

1.模板:

二分的写法保证最终答案处于闭区间[l,r]以内,循环以l=r结束,每次二分的中间值mid会归属于左半段与右半段二者之一。

(1)在单调序列a中查找>=x的数中最小的一个(即x或x的后继):

while (l < r)
{
   
   
    int mid = (l + r) >> 1;
    if (a[mid] >= x) 
        r = mid; 
    else 
        l = mid + 1;
}
return a[l];

(2)在单调序列a中查找<=x的数中最大的一个(即x或x的前驱):

while (l < r)
{
   
   
    int mid = (l + r + 1) >> 1;
    if (a[mid] <= x) 
        l = mid; 
    else 
        r = mid - 1;
}
return a[l];
2.理解:

​ 在第一段代码中,若a[mid]>=x,则根据序列a的单调性,mid之后的数会更大,所以>=x的最小的数不可能在mid之后,可行区间应该缩小为左半段。因为mid也可能是答案,故此时应该取r=mid。同理,若a[mid]<x,取l=mid+1。

​ 在第二段代码中,若a[mid]<=x,则根据序列a的单调性,mid之前的数会更小,所以<=x的最大的数不可能在mid之前,可行区间应该缩小为右半段。因为mid也可能是答案,故此时应该取l=mid。同理,若a[mid]>x,取r=mid-1。

3.注意:

①首先聊聊两者mid取法的区别:

第一种要求>=x的数最小的,所以mid要尽可能小,不+1,第二种要求<=x的数里面最大的,要从大了往小了搜,+1。

如上两种代码,这两种二分写法有两种形式:

  1. 缩小范围时,r = mid, l = mid + 1,取中间值时,mid = (l + r) >> 1
  2. 缩小范围时,l = mid, r = mid - 1,取中间值时,mid = (l + r + 1) >> 1

r和l的分支方法 与 mid的取法是配套的。下面给出简单证明:

如果取l = mid, r = mid - 1时mid = (l + r) >> 1。当r - l = 1时,mid = 2l,所以下一轮收缩范围,如果是l变,就变成l = l死循环,如果是r变,就会发生r < l,与我们While循环以l == r结束不符。

由此同样可证其余搭配,记住:l = mid的时候,mid的取法要+1

②>>和直接 /2 的区别:

右移运算是向下取整,而整数除法是向零取整,在二分值域包含负数时后者不能正常工作。

③仔细分析这两种mid的取法,我们还发现:mid=(l+r)>>1不会取到r这个值,mid=(l+r+1)>>1不会取到l这个值。我们可以利用这一性质来处理无解的情况,把最初的二分区间[1,n]分别扩大为[1,n+1]和[0,n],把a数组的一个越界的下标包含进来。如果最后二分终止于扩大后的这个越界下标上,则说明a中不存在所求的数。

4.使用流程:

(1)分析问题,左右半段哪个是可行区间,mid归属哪半段

(2)根据分析结果,

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值