二分

二分

介绍

相信大家小时候都玩过猜数字的游戏,一般来说,大家都是从中间开始猜,比如猜0~100之间的整数,先猜50,小了再猜75,大了再猜35。我们在玩这个游戏时就使用了二分这个思想,在算法竞赛中,我们对具有单调性的问题便可以使用二分,是一种非常好用的算法,但是二分里面的坑也非常多,稍有不慎便会漏掉答案或陷入死循环

整数二分

此为二分的示意图,我们在对问题进行求解的时候,先分析问题中有什么性质可以利用,根据这个性质找两个区间的边界,使得左边不满足或满足这个性质,右边满足或不满足这个性质,注意两个区间并没有交点(一个点不可能既满足又不满足)

根据区间究竟满足还是不满足,二分也有两个模板(一种 \(mid\) 落在左区间,另一种 \(mid\) 落在右区间):

第一种模型

这种模型 \(mid=(l+r)/2\),这里无需考虑边界。

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;
    }
    return l;
}

判断 \(mid\) 是否满足性质:
如果满足说明答案包括 \(mid\) \(r=mid\)
如果不满足说明答案包括 \(mid\) \(l=mid+1\)

第二种模型

这种模型的 \(mid = (l+r+1)/2\) 。这里因为计算机会自动去尾,例如当 \(l=0,r=1\) 时,如果不加一 \(mid\) 便会变成0,\(l=mid\) ,便会陷入死循环

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

判断 \(mid\) 是否满足性质:
如果满足说明答案包括 \(mid\) \(r=mid\)
如果不满足说明答案不包括 \(mid\) \(l=mid+1\)

浮点数二分

浮点数二分相对简单,不像整数二分需要考虑边界问题

精度问题

两种方式:

  • 设置一个精度 \(eps\) 循环条件是 \(r-l>eps\) 保留 \(k\) 位小数时 \(eps=10^-\)\(^(\)\(^k\)\(^+\)\(^2\)\(^)\)
  • 循环100次

每次根据 \(mid\) 确定是 \(r=mid\) \(l=mid\) 还是 \(l=mid\) \(r=mid\) 就行了

如何使用

关于无解的判断

\((l+r+1)/2\) \(mid\) 取不到 \(l\),因为 \(l=mid+1\) ,当 \(l=r\) 就退出,假设 \(mid\) 能取到 \(r\) ,那么 \(l=r+1\),与循环退出的条件不符

\((l+r)/2\) \(mid\) 取不到 \(r\),原因同上

两种判断方法:
因为二分保证有解,在循环结束时一定停在一个点上,所以衍生出了两种方法:
1、看这一个点是否满足要求,不满足就无解

2、\((l+r+1)/2\) 将原本 \([1,n]\) 的区间扩大到 \([1,n+1]\),如果最后停在了越界的下标上说明无解(其他点都不满足要求)

\((l+r)/2\)\([1,n]\) 扩大到 \([0,n]\),与上一个同理

适用场景

区间 \([l, r]\) 被划分成 \([l, mid]\)\([mid + 1, r]\) 时使用 第一个模板

区间 \([l, r]\) 被划分成 \([l, mid - 1]\)\([mid, r]\) 时使用 第二个模板

\((l+r)/2\) 适用于左区间不满足,右区间满足

\((l+r+1)/2\) 适用于左区间不满足,右区间满足

例题引入

给定一个数组,数组里的元素从小到大递增,找到 \(\geq x\) 的数中最小的一个

给定一个数组,数组里的元素从小到大递增,找到 \(\leq x\) 的数中最小的一个

详解:
当我们遇到最大最小这类字眼的时候,一般要使用二分,当然,二分有两个模板,究竟如何考虑呢

首先,数组是单调递增的,我们可以使用二分

如果要找 \(\leq x\) 的数,那么这个数应该比较小,我们应该在左边查找,所以我们使用第一个模板

如果要找 \(\geq x\) 的数,那么这个数应该比较大,我们应该在右边查找,所以我们使用第二个模板

二分查找

二分查找也被叫做折半查找,顾名思义,就是每次查找去掉不符合条件的一半区间,直到找到答案(整数二分)或者和答案十分接近(浮点二分)。在阅读题面时,我们要关注题目是最小值最大化还是最大值最小化

二分答案

二分答案适用于当答案属于一个区间,这个区间比较大,直接暴力会超时,最重要的是区间满足单调性,当这个答案越大(或越小),题目中的一个变量也会随之增大(或减少),通过check函数进行检验答案是否正确,根据结果放弃右半部分或左半部分

posted @ 2023-08-13 18:51  typerxiaozhu  阅读(46)  评论(0编辑  收藏  举报