二分需要满足两个条件:
(1)数组存储
(2)元素有序,单调性
时间复杂度:O( l o g 2 n log_2^n log2n)
整数二分算法模板
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;
}
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;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
Tips:1. 用模板 1 还是模板 2 可以先判断 if(check(mid)) 满足时:
① r = mid——模板1 (mid = l + r >> 1)
③ l = mid——模板2 (mid = l + r +1 >> 1)
- 当循环while( l < r ) 结束时,l =r
浮点数二分算法模板
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
Tips:
题目要求保留:①四位小数——eps = 1e-6
②五位小数——eps = 1e-7
③六位小数——eps = 1e-8
(while ( r - 1 > eps ) 可用100次for循环来代替,当 r - l 足够小时认为找到了答案)
什么是二分答案?
答案属于一个区间,当这个区间很大时,暴力超时。但重要的是——这个区间是对题目中的某个量有单调性的,此时,我们就会二分答案。每一次二分会做一次判断,看是否对应的那个量达到了需要的大小。相当于把答案从它可能所在的区间里二分出来。
判断:根据题意写个check函数,如果满足check,就放弃右半区间(或左半区间),如果不满足,就放弃左半区间(或右半区间)。一直往复,直至到最终的答案。
如何判断一个题是不是用二分答案做的呢?
1、答案在题目给的一个区间内(一般情况下,区间会很大,暴力超时)
2、直接搜索不好搜,但是容易判断一个答案可行不可行
3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。
此外,可能还会有一个典型的特征:求…最大值的最小 、 求…最小值的最大
补充:STL中的二分low_bound和upper_bound
lower_bound()用于在已排好序的数组中找出大于等于/小于等于 目标元素的下标最小的元素的地址。
upper_bound()用于在已排好序的数组中找出大于/小于目标元素的下标最小的元素的地址。
(返回迭代器) lower_bound (开始位置,结束位置,查找元素);
(返回迭代器) upper_bound(开始位置,结束位置,查找元素);
这两个函数都有三(四)个参数,第四个参数是被查找函数的排序方式,如果不填就默认为从小到大排序。
第一个参数是被查找数组的首地址,第二个参数是末地址,第三个是要目标元素,第四个是被查数组的排序方式。
被查数组排序方式写的时候返回值应为bool类型,设定两个参数(与被查数组内元素类型相同即可)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int cmd(int a, int b)
{
return a > b;
}
int main()
{
int a[7] = {1, 2, 3, 7, 7, 9,15};
sort(a, a+7);
int pos1 = lower_bound(a, a+7, 7) - a;
int pos2 = upper_bound(a, a+7, 15) - a;
cout << pos1 << " " << pos2 << endl;
sort(a, a+7, cmd);
int pos3 = lower_bound(a, a+7, 2, greater<int>()) - a;
int pos4 = upper_bound(a, a+7, 1, greater<int>()) - a;
cout << pos3 << " " << pos4 << endl;
return 0;
}
//输出:
3 7
5 7