数的范围 刷题笔记

思路 寻找第一个大于等于目标的 数

因为该数组是升序的 所以 我们可以采用二分的方式

逼近答案

定义一个左指针和一个右指针

当左右指针重合时 

就是我们要找的答案

当我们寻找第一个大于等于x的数时

a[mid]>=x,答案在mid处 或者在mid的左边

因此让r=mid继续逼近

如果中间值小于x说明答案在右边

并且必定不在mid 处

因此让l=mid+1;

下面寻找右端点

当a[mid]<=x;

说明答案在mid 处或者在mid 的右边

因此让l=mid;

否则让r=mid-1;

为了避免陷入死循环

我们要讨论特殊情况

例如 当l指向3,r指向4,;

且3为左端点 4为右端点

寻找左端点时

mid=(3+4)>>1=3;

此时a[3]=x,让r=mid=3;

完成重合

当寻找右端点时 如果还是

mid=(l+r)>>1;

a[mid]=x,让l=mid=3,并未发生改变 陷入了死循环

因此我们在找右端点要+1 让mid上取整

mid=(l+r+1)/2=4;

此时 让l=mid=4;

完成重合  

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,q;
const int N=1e5+10;
int a[N]; 

int main(){
    cin>>n>>q;
    for(int i=0;i<n;i++){
        cin>>a[i];
        
    }    
    while(q--){
        int x;
        cin>>x;
        int l=0,r=n-1;
        while(l<r){
            int mid=l+r>>1;
            if(a[mid]>=x){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        if(a[r]==x)
        {
            cout<<r<<' ';
            int r=n-1;
            while(l<r){
                int mid=l+r+1>>1;
                if(a[mid]<=x){
                    l=mid;
                }else{
                    r=mid-1;
                }
            }
            cout<<r<<endl;
        }else
        {
            cout<<-1<<' '<<-1<<endl;
        }
        
    }
    return 0;
}

关键点在于讨论特殊情况

c++的除法为下取整

两指针位于相邻位置时

如何调整算法

来让二分不会陷入死循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值