二分
注意事项
- 求第一出现位置 相当于lower_bound()
- 求最后一次出现的位置后面一个位置,相当于upper_bound()
- 二分只是枚举的一种方式
- for循环是每个都遍历
- 满足check()的答案只有一个,就不用分左边界,右边界了,或者说左边界就等于右边界 l=r=x
- 满足check()的答案是一个范围l,r,也就是要根据题目意思得到左边界或者右边界
区分左边界还是右边界,主要看check(m)满足的情况下移动r还是l
如果要得到左边界则r = m, 右边界就是 l = m;
标准二分
左边界
找左边界时,选择mid偏左,mid = (l + r) >> 1
int bsearch_1(int l, int r){ while (l < r){ int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; } 注意这个mid分到了左边区间,因为我们是寻找左边界 [l,mid] [mid+1,r] 如果mid满足条件,就查找[l,mid]区间
右边界
找右边界时,选择mid偏右,mid = (l + r + 1) >> 1
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分到了右边区间,因为我们是寻找右边界 [l,mid-1] [mid,r] 如果mid满足条件,就查找[mid,r]区间
整数二分
bool check(int mid) { // 检查 mid 是否可行 } int binary_search() { int l = 0, r = max_ans; // 求最大值 右边界 while (l < r) { int mid = (l + r + 1) >> 1; if (check(mid)) { l = mid; } else { r = mid - 1; } } return l; } int binary_search() { int l = 0, r = max_ans; // 求最小值 左边界 while (l < r) { int mid = (l + r) >> 1; if (check(mid)) { r = mid; } else { l = mid + 1; } } return l; }
数组二分
用check函数来找有序数组的值
// 在nums找到最左边的2和最右边的2 vector<int> nums{1,2,2,2,3}; int val = 2; // 右边界 bool check(int mid) { // 检查 mid 是否可行 return nums[mid] <= val; } int binary_search() { int l = 0, r = nums.size(); // 求最大值 右边界 while (l < r) { int mid = (l + r + 1) >> 1; if (check(mid)) { l = mid; } else { r = mid - 1; } } return l; } // 左边界 bool check(int mid) { // 检查 mid 是否可行 return nums[mid] >= val; } int binary_search() { int l = 0, r = nums.size(); // 求最小值 左边界 while (l < r) { int mid = (l + r) >> 1; if (check(mid)) { r = mid; } else { l = mid + 1; } } return l; }
// 无边界 vector<int> nums{1,2,2,2,3}; int val = 2; int binary_search() { // nums 从小到大 int l = 0, r = nums.size()-1, ans=-1; // 求最大值 右边界 while (l <= r) { int mid = (l + r) >> 1; if (nums[mid] == val) { ans = mid; break; }if(nums[mid] < val){ l = mid+1; } else { r = mid - 1; } } return ans; } // 右边界 int bsearch(int a[], int l, int r, int v) {//查找区间是[x,y) 返回的位置却可能是 y while (l < r) { int m = (l + r + 1) >> 1; if(a[m] == v) l = m; else if(a[m] > v) r = m - 1; else l = m; } return l; } // 左边界 int bsearch(int a[], int l, int r, int v) {//查找区间是[x,y) 返回的位置却可能是 y while (l < r) { int m = (l + r) >> 1; if(a[m] == v) r = m; else if (a[m] > v) r = m; else l = m + 1; } return l; }
浮点数二分
浮点数eps,这里保留两位小数,1e-2往后再保留两位就行,1e-4
double binary_search() { double l = 0, r = max_ans; // 求最大值 右边界 while(r - l > eps){ double mid = (l+r)/2; if(check(mid)) l = mid; else r = mid; } return l; //return r; } double binary_search() { double l = 0, r = max_ans; // 求最大值 左边界 while(r - l > eps){ double mid = (l+r)/2; if(check(mid)) r = mid; else l = mid; } return l; //return r; } 因为r - l > eps 所以r l值几乎相等,返回哪个都一样