lower_bound() 与 upper_bound()函数的介绍与应用

        在学习二分算法时了解到了lower_bound()函数与upper_bound()函数。这是c++标准库中的提供的两个非常有用的二分查找函数,定义在头文件中。他们都要求输入范围是已排序的,才能正常工作。这里我基于deepseek的回答对于这两个函数做一个总结。

lower_bound

       功能:lower_bound返回指向第一个不小于给定值的元素的迭代器(返回的是一个指针)。

       行为:

        1,在已排序的[first, last)范围内查找第一个不小于value的元素

        2,如果所有元素都小于value,则返回last

        3,时间复杂度:O(log n)(对于随机访问迭代器)

        示例:

vector v = {1, 2, 4, 4, 5, 6};
auto it = lower_bound(v.begin(), v.end(), 4); // 指向第一个4
auto it2 = lower_bound(v.begin(), v.end(), 3); // 指向第一个4
auto it3 = lower_bound(v.begin(), v.end(), 7); // 返回v.end()

upper_bound 

       功能:upper_bound返回指向第一个大于给定值的元素的迭代器(返回的是一个指针)。    

       行为:

        1,在已排序的[first, last)范围内查找第一个大于value的元素

        2,如果所有元素都不大于value,则返回last

        3,时间复杂度:O(log n)(对于随机访问迭代器)

        示例:

vector v = {1, 2, 4, 4, 5, 6};
auto it = upper_bound(v.begin(), v.end(), 4); // 指向5
auto it2 = upper_bound(v.begin(), v.end(), 6); // 返回v.end()

两者区别

特性 lower_bound upper_bound
查找条件 第一个不小于value 第一个大于value
返回值 可能等于value 一定大于value
典型用途 查找插入位置(保持有序) 查找范围上界

 

实际应用

        1,查找元素是否存在

bool exists = binary_search(v.begin(), v.end(), value);
// 等价于
bool exists = lower_bound(v.begin(), v.end(), value) != v.end() && 
              *lower_bound(v.begin(), v.end(), value) == value;

        2 ,统计某值的出现次数:

int count = upper_bound(v.begin(), v.end(), value) - 
            lower_bound(v.begin(), v.end(), value);

        3,在有序序列中插入元素: 

v.insert(lower_bound(v.begin(), v.end(), new_value), new_value);

    这两个函数是高效操作有序序列的基础工具,在竞赛编程和实际工程中都有广泛应用。

            在当时的deepseek回答完我之后,我就产生了一个疑惑,lower_bound和upper_bound这两个函数的功能不会重复吗?在经过深度的思考过后,我终于明白了这两个函数的设计不是重复的,而是互补的,它们一起可以精确确定一个值在有序序列中的范围。

    下面提供一个相关的题:P8667 [蓝桥杯 2018 省 B] 递增三元组 - 洛谷

    题目描述

    给定三个整数数组 A=[A1​,A2​,⋯,AN​],B=[B1​,B2​,⋯,BN​],C=[C1​,C2​,⋯,CN​]。

    请你统计有多少个三元组 (i,j,k) 满足:

    1. 1≤i,j,k≤N
    2. Ai​

    输入格式

    第一行包含一个整数 N。

    第二行包含 N 个整数 A1​,A2​,⋯,AN​。

    第三行包含 N 个整数 B1​,B2​,⋯,BN​。

    第四行包含 N 个整数 C1​,C2​,⋯,CN​。

    输出格式

    一个整数表示答案

    输入输出样例

    输入 #1

    3
    1 1 1
    2 2 2
    3 3 3

    输出 #1

    27

            如题所示,该题可以先将a,b,c三个数组进行排序。由数学关系不难看出,递增三元组的个数即对于数组b中的每一位数字,寻找在数组a中小于其数的个数乘以,在数组c中大于其数的个数。所以就可以从1到n进行遍历,在数组a中寻找小于b[i]的数的个数,在数组c中寻找大于b[i]的数的个数,然后再将它们相乘并累加起来,即可得到最终的答案。

            由此思路,就可以把b[i]当作所寻找的值,利用lower_bound和upper_bound来分别在数组a和数组b中小于和大于s[i]的数的个数。 

    具体代码如下:

    #include 
    #include 
    #include 
    using namespace std;
    
    int main()
    {
        int n;
        long long res = 0;
        cin>>n;
        vector a(n),b(n),c(n);
        for (int i = 0;i < n;++i){
            cin>>a[i];
        }
        for (int i = 0;i < n;++i){
            cin>>b[i];
        }
        for (int i = 0;i < n;++i){
            cin>>c[i];
        }
        sort(a.begin(),a.end());
        sort(c.begin(),c.end());
        for (int i = 0;i < n;++i){
            //cnt1为数组a中第一个等于b[i]的数组下标,即小于b[i]的数量
            long long cnt1 = lower_bound(a.begin(),a.end(),b[i]) - a.begin();
            //cnt2为数组c中第一个大于b[i]的数组下标,n - cnt2即为大于b[i]的个数
            long long cnt2 = upper_bound(c.begin(),c.end(),b[i]) - c.begin();
            //累加结果
            res += cnt1 * (n - cnt2);
        }
        cout<

    你可能感兴趣的:(二分,算法,数据结构)