二分

注意事项

  • 求第一出现位置 相当于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值几乎相等,返回哪个都一样