算法笔记_079:蓝桥杯练习 区间k大数查询(Java)

目录

1 问题描述

2 解决方案

 


1 问题描述

问题描述

给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。

输入格式

第一行包含一个数n,表示序列长度。

第二行包含n个正整数,表示给定的序列。

第三个包含一个正整数m,表示询问个数。

接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。

输出格式

总共输出m行,每行一个数,表示询问的答案。

样例输入

5
1 2 3 4 5
2
1 5 2
2 3 2

样例输出

4
2

数据规模与约定

对于30%的数据,n,m<=100;

对于100%的数据,n,m<=1000;

保证k<=(r-l+1),序列中的数<=106。


2 解决方案

本题主要考查排序,考虑到时间效率和稳定性,此题选择合并排序最佳。

具体代码如下:

import java.util.Scanner;

public class Main {
    //对数组array中下标start到end中的元素进行归并并排,求得该区间的降序排列
    public void mergeSort(int[] array, int start, int end) {
        if(end - start >= 1) {
            int[] leftArray = getHalfArray(array, start, end, 0);
            int[] rightArray = getHalfArray(array, start, end, 1);
            mergeSort(leftArray, 0, leftArray.length - 1);
            mergeSort(rightArray, 0, rightArray.length - 1);
            getMerge(array, start, leftArray, rightArray);

        }
    }
    //根据judge获取数组array区间start~end的一半元素
    public int[] getHalfArray(int[] array, int start, int end, int judge) {
        int[] half;
        int len = end - start + 1;
        if(judge == 0) {
            int length = len / 2;
            half = new int[length];
            for(int i = 0;i < length;i++)
                half[i] = array[start + i];
        } else {
            int length = len - len / 2;
            half = new int[length];
            for(int i = 0;i < length;i++) {
                half[i] = array[start + len / 2 + i];
            }
        }
        return half;
    }
    //合并数组array的左半边元素和右半边元素,返回降序排列
    public void getMerge(int[] array, int start, int[] leftArray, int[] rightArray) {
        int i = 0, j = 0;
        while(i < leftArray.length && j < rightArray.length) {
            if(leftArray[i] >= rightArray[j])
                array[start++] = leftArray[i++];
            else
                array[start++] = rightArray[j++];
        }
        while(i < leftArray.length) array[start++] = leftArray[i++];
        while(j < rightArray.length) array[start++] = rightArray[j++];
    }

    public void printResult(int[] array, int[][] query) {
        int[] result = new int[query.length];
        for(int i = 0;i < query.length;i++) {
            int[] tempArray = new int[array.length];  //此处获取array的克隆对象,要求地址也要改变。若直接赋值,两者地址是一样
            for(int j = 0;j < array.length;j++)
                tempArray[j] = array[j];
            int start = query[i][0];
            int end = query[i][1];
            int k = query[i][2];
            if(k < 0 || k > end - start + 1)   //防止k出界
                continue;
            mergeSort(tempArray, start - 1, end - 1);
            result[i] = tempArray[start - 1 + k - 1];
        }
        //输出结果
        for(int i = 0;i < result.length;i++)
            System.out.println(result[i]);
    }

    public static void main(String[] args) {
        Main test = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] array = new int[n];
        for(int i = 0;i < array.length;i++)
            array[i] = in.nextInt();
        int m = in.nextInt();
        if(n > 1000 || m > 1000)
            return;
        int[][] query = new int[m][3];
        for(int i = 0;i < m;i++) {
            query[i][0] = in.nextInt();
            query[i][1] = in.nextInt();
            query[i][2] = in.nextInt();
        }
        test.printResult(array, query);
    }
}
时间: 2024-12-22 08:37:58

算法笔记_079:蓝桥杯练习 区间k大数查询(Java)的相关文章

蓝桥杯ALGO-1,区间k大数查询

#include<stdio.h> int devide(long a[],int low,int high){ long key=a[high]; while(low<high){ while(low<high&&a[low]>key){ low++; } if(low<high) a[high--]=a[low]; while(low<high&&a[high]<key){ high--; } if(low<high

算法笔记_063:蓝桥杯练习 送分啦(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 这题想得分吗?想,请输出"yes":不想,请输出"no". 输出格式 输出包括一行,为"yes"或"no". 2 解决方案 初步一看,这题竟然没有输入输出示例,不过也不难吧.好吧,第一次,代码长这样: import java.util.Scanner; public class Main{ public static void main(String[] args)

算法笔记_123:蓝桥杯第七届省赛(Java语言B组部分习题)试题解答

 目录 1 凑算式 2 方格填数 3 四平方和   1 凑算式 凑算式 B DEF A + --- + ------- = 10 C GHI (如果显示有问题,可以参见[图1.jpg]) 这个算式中A~I代表1~9的数字,不同的字母代表不同的数字. 比如: 6+8/3+952/714 就是一种解法, 5+3/1+972/486 是另一种解法. 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字. (碰到除法问题,要特别注意,如题目未事先声明进行整除,均首先消

蓝桥杯--算法训练 区间k大数查询

算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 51 2 3 4 521 5

1501130926-蓝桥杯- 算法训练 区间k大数查询

算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 5 1 2 3 4 5 2 1

算法训练——区间K大数查询

//区间K大数查询 #include<stdio.h> int main(){ int n,m,l,r,k,index = 0; scanf("%d",&n); int a[n]; for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); while(m--){ int b[n]; scanf("%d%d%d",&l,&a

[ALGO-1] 区间k大数查询

算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 5 1 2 3 4 5 2 1

区间k大数查询

import java.util.*; import java.io.*; public class 区间k大数查询 { public static void main(String[] args){ Scanner in=new Scanner(new BufferedInputStream(System.in)); int n = in.nextInt(); int[] num = new int[n]; for (int i = 0; i < n; i++) { num[i] = in.n

算法笔记_076:蓝桥杯练习 结点选择(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多少? 输入格式 第一行包含一个整数 n . 接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值. 接下来一共 n-1 行,每行描述树上的一条边. 输出格式 输出一个整数,代表选出的点的权值和的最大值. 样例输入 51 2 3 4 51 21 32 42 5 样例输出 12 样例说明