数的范围 Java

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

思路
先讲一下一开始我是怎么怎么写的吧,希望大家引以为戒,题目让我们找的是给定数字的第一次出现的位置和最后一次出现的位置,我这一想String.lastIndexOf() , String.indexOf()不就是干这个事的么,找不到还返回-1,这绝配啊,后来相信大家也猜的到打脸了,这个虽然给的例子能过,但是这个方法只适合个位数,10这个数长两个单位,但是它既包含1,又包含0,结果也可想而知,诶还是经过y总讲二分,才弄出来
这题大体思路是二分法,如果有对二分法不大了解的可以上网搜一下这个方法蓝桥杯中还挺实用的。
1.我们先找出x第一次出现的位置

            int l=0;
            int r=n-1;
            while (l<r){
                int mid=(l+r)/2;
                if(arr1[mid]>=arr2[i])
                    r=mid;
                else
                    l=mid+1;
               }

2.如果第一次找到了,我们就利用上次的l的值作为新的左边界,右边界还是n-1

            int ansl=l;
             r=n-1;
            while (l<r){
                int mid=(r+l+1)/2;//这里加1是为了防止死循环
                //假设最后循环到l=r-1,只剩下两个数,mid=(l+r)/2的话,由于是向下取整
                //所以l=mid,如果此时arr1[mid]<=arr2[i],l=mid就会产生死循环
                if(arr1[mid]<=arr2[i])
                    l=mid;
                else
                    r=mid-1;
            }

然后就全部代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int q=input.nextInt();
        int res[][]=new int[q][3];
        int arr1[]=new int[n];
        int arr2[]=new int [q];
        for(int i=0;i<n;i++)
            arr1[i]=input.nextInt(); 
        for(int i=0;i<q;i++){
            arr2[i]=input.nextInt();//需要查找的数我们存到一个数组里
        }
        for(int i=0;i<q;i++){
            int l=0;
            int r=n-1;
            while (l<r){
                int mid=(l+r)/2;
                if(arr1[mid]>=arr2[i])
                    r=mid;
                else
                    l=mid+1;
            }
            //如果找到了最左边的那个,就继续找右边那个,如果没有直接输出“-1 -1”
            if(arr1[l]==arr2[i]){
              int ansl=l;
                 r=n-1;
                while (l<r){
                    int mid=(r+l+1)/2;
                    if(arr1[mid]<=arr2[i])
                        l=mid;
                    else
                        r=mid-1;
                }
                System.out.println(ansl+" "+r);

            }
            else
                System.out.println("-1 -1");

        }

    }
}

总结:
y总讲了两个二分的模板,分别是
1.l=mid,r=mid-1,此时的mid就必须是要由 (r+l+1)/2 所得,原因上面说过了;
2. r=mid,l=mid+1,此时mid由(r+l)/2所得;
这两个模板一个是找最左边的,一个找最右边的,我的理解是一个找最小的,一个找最大的,在我为数不多的题解中还有一篇“分巧克力”,我就是按找最大的边,来用第一种方法的,大家有兴趣的可以看看,请大家对于的我上面的理解不要太当真,我的理解是一个找最小的,一个找最大的,就是这个,因为我不知道有没有问题,没准是个偶然,不想误人子弟,

猜你喜欢

转载自blog.csdn.net/qq_44844588/article/details/106898148