二分总结

二分总结

命名规则
为描述方便,下面文中提示的:

升序理解为不降序,即按顺序输入的数字,每个数字对比前面的数字,可等于可大于,但不能小于。

降序理解为不升序,即按顺序输入的数字,每个数字对比前面的数字,可等于可小于,但不能大于。

一、函数定义与用途

lower_bound

用途
升序的情况下,lower_bound返回第一个 大于等于val的位置。

降序的情况下,lower_bound返回第一个 小于等于val的位置。

upper_bound
用途
升序的情况下,upper_bound返回第一个 大于val的位置。

降序的情况下,upper_bound返回第一个 小于val的位置。


二、STL内置方法

lower_bound

升序

int p = lower_bound(q, q + n, x) - q;

降序

int p = lower_bound(q, q + n, x, greater<int>()) - q;

upper_bound

升序

int p = upper_bound(q, q + n, x) - q;

降序

int p = upper_bound(q, q + n, x, greater<int>()) - q;

二、手写左闭右开(推荐写法)

升序

int lower_bound(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int upper_bound(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] > x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

降序

int lower_bound(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] <= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int upper_bound(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] < x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

三、手写左闭右闭

升序

int lower_bound(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] < x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int upper_bound(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] <= x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

降序

int lower_bound(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] > x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int upper_bound(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] >= x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

四、升序测试完整代码

#include <bits/stdc++.h>

using namespace std;

const int N = 8;
int q[N] = {1, 2, 3, 4, 6, 7, 8, 9};

//本代码测试升序(不下降)的lower_bound和upper_bound情况
//前提是有序的情况下,lower_bound返回第一个大于等于x值的位置。(通过二分查找)

//左闭右开
int lower_bound1(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int upper_bound1(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] > x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

//左闭右闭
int lower_bound2(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] < x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int upper_bound2(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] <= x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int main() {
    //在升序情况下,lower_bound理解为求大于等于x的第一个位置
    // 1、数组中存在
    printf("%d ", lower_bound1(q, 0, 8, 4));
    printf("%d ", lower_bound2(q, 0, 7, 4));
    printf("%d\n", int(lower_bound(q, q + 8, 4) - q));

    // 2、数组中不存在
    printf("%d ", lower_bound1(q, 0, 8, 5));
    printf("%d ", lower_bound2(q, 0, 7, 5));
    printf("%d\n", int(lower_bound(q, q + 8, 5) - q));
    // 3、数组左侧
    printf("%d ", lower_bound1(q, 0, 8, 0));
    printf("%d ", lower_bound2(q, 0, 7, 0));
    printf("%d\n", int(lower_bound(q, q + 8, 0) - q));
    // 4、数组右侧
    printf("%d ", lower_bound1(q, 0, 8, 10));
    printf("%d ", lower_bound2(q, 0, 7, 10));
    printf("%d\n", int(lower_bound(q, q + 8, 10) - q));

    puts("==================================");
    //在升序情况下,upper_bound理解为求大于x的第一个位置
    // 1、数组中存在
    printf("%d ", upper_bound1(q, 0, 8, 4));
    printf("%d ", upper_bound2(q, 0, 7, 4));
    printf("%d\n", int(upper_bound(q, q + 8, 4) - q));
    // 2、数组中不存在
    printf("%d ", upper_bound1(q, 0, 8, 5));
    printf("%d ", upper_bound2(q, 0, 7, 5));
    printf("%d\n", int(upper_bound(q, q + 8, 5) - q));
    // 3、数组左侧
    printf("%d ", upper_bound1(q, 0, 8, 0));
    printf("%d ", upper_bound2(q, 0, 7, 0));
    printf("%d\n", int(upper_bound(q, q + 8, 0) - q));
    // 4、数组右侧
    printf("%d ", upper_bound1(q, 0, 8, 10));
    printf("%d ", upper_bound2(q, 0, 7, 10));
    printf("%d\n", int(upper_bound(q, q + 8, 10) - q));

    return 0;
}

五、降序测试完整代码

#include <bits/stdc++.h>

using namespace std;
const int n = 8;
int q[n] = {9, 8, 7, 6, 4, 3, 2, 1};

//本代码测试降序(不上升)的lower_bound和upper_bound情况

//左闭右开
int lower_bound1(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] <= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int upper_bound1(int q[], int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) / 2;
        if (q[mid] < x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

//左闭右闭
int lower_bound2(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] > x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int upper_bound2(int q[], int l, int r, int x) {
    while (l <= r) {
        int mid = (l + r) / 2;
        if (q[mid] >= x)
            l = mid + 1;
        else
            r = mid - 1;
    }
    return l;
}

int main() {
    //在降序情况下,lower_bound理解为求小于等于x的第一个位置
    // 1、数组中存在
    printf("%lld ", lower_bound(q, q + n, 4, greater<int>()) - q); //返回第一次出现的位置
    printf("%d ", lower_bound1(q, 0, n, 4));
    printf("%d \n", lower_bound2(q, 0, n - 1, 4));

    // 2、数组中不存在
    printf("%lld ", lower_bound(q, q + n, 5, greater<int>()) - q); //返回第一个插入x不影响原序列顺序的位置
    printf("%d ", lower_bound1(q, 0, n, 5));
    printf("%d \n", lower_bound2(q, 0, n - 1, 5));

    // 3、数组左侧
    printf("%lld ", lower_bound(q, q + n, 10, greater<int>()) - q); //返回0
    printf("%d ", lower_bound1(q, 0, n, 10));
    printf("%d\n", lower_bound2(q, 0, n - 1, 10));

    // 4、数组右侧
    printf("%lld ", lower_bound(q, q + n, 0, greater<int>()) - q); //返回最后一个元素下标+1
    printf("%d ", lower_bound1(q, 0, n, 0));
    printf("%d\n", lower_bound2(q, 0, n - 1, 0));

    puts("==================================");
    //在降序情况下,upper_bound理解为求小于x的第一个位置 
    // 1、数组中存在
    printf("%lld ", upper_bound(q, q + n, 4, greater<int>()) - q); //返回第一次出现的位置
    printf("%d ", upper_bound1(q, 0, n, 4));
    printf("%d\n", upper_bound2(q, 0, n - 1, 4));

    // 2、数组中不存在
    printf("%lld ", upper_bound(q, q + n, 5, greater<int>()) - q); //返回第一个插入x不影响原序列顺序的位置
    printf("%d ", upper_bound1(q, 0, n, 5));
    printf("%d\n", upper_bound2(q, 0, n - 1, 5));

    // 3、数组左侧
    printf("%lld ", upper_bound(q, q + n, 10, greater<int>()) - q); //返回0
    printf("%d ", upper_bound1(q, 0, n, 10));
    printf("%d\n", upper_bound2(q, 0, n - 1, 10));

    // 4、数组右侧
    printf("%lld ", upper_bound(q, q + n, 0, greater<int>()) - q); //返回最后一个元素下标+1
    printf("%d ", upper_bound1(q, 0, n, 0));
    printf("%d\n", upper_bound2(q, 0, n - 1, 0));

    return 0;
}

六、经验总结

  • 二分模板在网上非常多,在边界处理上有各种各样的处理方式,感受后,认为STL的思路是最好的:左闭右开

  • 一般来讲,STL可以处理大于等于,大于,小于等于,小于,就基本够用了,原则上能用STL的二分办法解决的,尽量用STL,实在不行的,使用手写的左闭右开区间办法。(挖坑待填,啥样是实在不行呢?)

  • 查找左边界,可以直接lower_bound,如果想要查找右边界,可以使用upper_bound然后再减1

posted @   糖豆爸爸  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2021-07-13 P1036 选数题解
2021-07-13 十进制转二进制方法整理
2021-07-13 P1157组合数的输出 题解
2019-07-13 mount.cifs Windows共享目录权限755问题
2018-07-13 挑战扫雷世界纪录
2018-07-13 centos java tomcat 中文乱码解决办法
2017-07-13 杀掉TOMCAT并重启的脚本
Live2D
点击右上角即可分享
微信分享提示