AcWing 789. 数的范围

AcWing 789. 数的范围

一、题目描述

给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。

如果数组中不存在该元素,则返回 -1 -1

输入格式
第一行包含整数 nq,表示数组长度和询问个数。

第二行包含 n 个整数(均在 110000 范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式
q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1

数据范围

1n100000
1q10000
1k10000

输入样例:

6 3
1 2 2 3 3 4
3
4
5

输出样例:

3 4
5 5
-1 -1

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

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

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

二、函数定义与用途

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;
}

五、经验总结

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

  • 一般来讲,STL可以处理大于等于,大于,小于等于,小于,一般的数字二分够用

  • 但是,由于二分不一定是数字二分,有时需要用check函数,这里STL就无法使用check函数了,所以,终极解法还是手写二分,容易扩展! 

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

六、实现代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
int n;
int q[N];
// 左闭右开 [ )
int lower_bound(int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) >> 1;
        if (q[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int upper_bound(int l, int r, int x) {
    while (l < r) {
        int mid = (l + r) >> 1;
        if (q[mid] > x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int main() {
    int T;
    cin >> n >> T;
    for (int i = 0; i < n; i++) cin >> q[i];

    while (T--) {
        int x;
        cin >> x;
        int p = lower_bound(0, n, x); //[0,n)
        if (q[p] != x) {
            puts("-1 -1");
            continue;
        }
        printf("%d ", p);
        p = upper_bound(0, n, x);
        printf("%d\n", p - 1);
    }
    return 0;
}
posted @   糖豆爸爸  阅读(1369)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2018-09-06 服务网与各地落地平台的调用关系
2016-09-06 mysql打开文件数太多的解决办法
2016-09-06 人人通数据库位置
2014-09-06 假期结束后的工作安排
2014-09-06 GZIP压缩占用CPU大吗?
Live2D
点击右上角即可分享
微信分享提示