789. 数的范围

题目

给定一个按照升序排列的长度为 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

 分析

对于输入 数组1 2 2 3 3 4,如果k=3,则输出为 “3(第一次出现的下标) 4(最后出现的下标) ”

数组有序,使用二分的思想可较好的解决,怎么二分呢?每一次二分的结果都只能有一个结果,所以分两次二分,一次找到最左边的3,一次找到最右边的3;

对于最左边的3,利用二分的思想,他就是想到找到的值,如果arr[mid]的值大于等于3,则right = mid(用等于是因为arr[mid]可能是目标值),否则left = mid+1(arr[mid]不可能是目标值,向右移移一位);

对于最右边的3,利用二分的思想,他就是想到找到的值,如果arr[mid]的值小于等于3,则left = mid(用等于是因为arr[mid]可能是目标值),否则right= mid-1(arr[mid]不可能是目标值,向左移一位);

代码

import java.util.*;
public class Main{
    public static void main(String arg[]){
        Scanner sc  = new Scanner(System.in);
        int n = sc.nextInt();
        int q = sc.nextInt();
        int[] temp = new int[n];
        for(int i = 0;i<n;i++){
            temp[i] = sc.nextInt();
        }
        for(int j = 0;j<q;j++){
            int k  = sc.nextInt();
            int l = 0;
            int r = n-1;
            while(l<r){
                int mid = l+r >>1;
                if(temp[mid] >= k){//左边界
                    r = mid;
                }else{
                    l = mid +1;
                }
            }
            if(temp[l] != k){//没有目标值,此时temp[l]为大于k的第一个值
                System.out.println("-1 -1");
                continue;
            }else{
                 System.out.print(l+" ");
            }
            l = 0;
            r = n-1;
            while(l<r){
                int mid = l+r+1>>1; //+1处理边界 有减一需加一
                if(temp[mid] <= k){//右边界
                    l = mid;
                }else{
                    r = mid -1;
                }
            }
            System.out.println(l);
            
        }
        
        
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值