求整数序列中出现次数最多的数_【每日算法】基础算法——整数二分查找[数的范围](五)...

题目内容

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

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

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

输入格式

第一行包含整数n和q,表示数组长度和询问个数。

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

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

输出格式

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

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

数据范围

1≤n≤100000

1≤q≤10000

1≤k≤10000

输入样例

6 3

1 2 2 3 3 4

3

4

5

输出样例

3 4

5 5

-1 -1

题解

本题采用整数二分查找的思想求解。

首先,二分查找可以根据某个具体的性质,将某个区间切分为两部分,一部分满足性质,另一部分不满足性质,那么二分查找是可以找到其满足性质的边界点,这是二分查找的核心本质。因此,二分查找,就是求根据某个性质而产生的边界点。

那么,我们可以有如下思考,这里给出一张图,根据图来进行说明。

c286977230ba2277c69a0871e69a7639.png

L和R代表序列的左右边界,黄色区间和红色区间是按照是否满足某个性质而产生的两段,若求黄色和红色的分界点,且设置黄色区间不满足分界性质,红色区间满足分界性质,思考如下:

  • 当求黄色部分的分界点时:

    • 假设mid=(L+R+1)/2,check函数为判断某个点是否满足黄色区间的性质,返回true或false。( 这里mid的定义(L+R+1)/2中的+1是避免出现死循环,具体可以思考当l=r-1时,若不加上1,就会出现死循环 )

    • 若check(mid)为true,则说明,mid这个点满足条件,因此,分界点一定在其右边,因此接下来需要二分的区间应该是[mid,r],将l=mid;若check(mid)为false,则说明,mid这个点不满足条件,因此分界点一定在其左边,因此接下来需要二分的区间应该是[l,mid-1],r=mid-1。

  • 当求红色部分的分界点时:

    • 假设mid=(L+R)/2, check函数为判断某个点是否满足红色区间的性质,返回true或false。

    • 若check(mid)为true,则说明,mid这个点满足这个性质,因此分界点应该在mid点的左边即二分的区间应该是[l,mid],r=mid;若check(mid)为false,则说明,mid这个点不满足这个性质,因此分界点应该在mid点的右边,即二分的区间应该是[mid+1,r],l=mid+1。

回到题中,我们可以进行如下思考:

因为题目中求某个数的范围,因此,边界有两个,一个是大于等于x,一个是小于等于x,对每个性质分别使用二分查找的方法求出分界点即可。

代码

#include using namespace std;const int N = 100010;int n,m;int q[N];int main(){    scanf("%d%d",&n,&m);    for (int i = 0; i< n; i++) scanf("%d",&q[i]);        while(m--){        int x;        scanf("%d",&x);                int l=0,r=n-1;        //求左边界        while(l            int mid=l+r >> 1;            if (q[mid] >= x) r= mid;            else l =mid+1;        }                if (q[l] != x) cout<<"-1 -1"<        else{            cout << l << ' ';            int l=0,r=n-1;            //求右边界            while(l                int mid=(l+r+1)>>1;                if (q[mid]<=x)l=mid;                else r = mid-1;            }            cout<        }    }    return 0;}

2fb7d5d7f478714b79c56ee58eca15b9.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值