2020/9/24 Acwing-快速查找算法-第k个数

题目

给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列的第k小的数是多少。
输入格式
第一行包含两个整数 n 和 k。
第二行包含 n 个整数(所有整数均在1~109范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第k小数。
数据范围
1≤n≤100000,
1≤k≤n
输入样例:
5 3
2 4 1 5 3
输出样例:
3

题目分析

本题题目要求使用快速选择算法,因为题目只要求找到第k小个数,那么利用快速排序算法,可以把整个数组分成两个部分,只需看k与左半部分数组长度的关系:如果k>左半边数组的个数,那么这第k个数一定在右半边;如果k<=左半边数组的个数,那么第k个数一定在左半边.这样,相比于全部排序,通过判断,只需要对一半的数组进行排序.
(主要是左边数组全部小于右边数组,如果左边数组有3个数,而想要找第二个小的数,就只要在左边找第二小的即可;找第5小的数,则需要在右边数组寻找.)

算法细节

因为题目属于查找算法,因此应该返回查找到的数,这样函数类型应该是int型.

1.确定函数功能
输入被查找的数组,输入查找的左右边界,输入要查找的是第几小的条件,就会返回查找到的数值.
2.实现方式
递归算法都是在函数中调用自己,也就是说在设计时可以把调用的那个函数当做已经实现的函数,利用其功能即可.
第一步:将整个函数分成大于x,与小于x(x可以随便取)两部分,这个步骤与快速排序算法相同.
第二步:判断第一部分的数组长度length与k的大小比较,如果length>=k,直接调用自身,修改区间为(起始为l,结尾为j,查找第k小),就可以直接返回答案.(因为我们假定这个功能已经实现了.)
如果length<k,则修改区间为(起始为j+1,结尾为r,查找第k-length小的(因为前length小的一定都在前面了)),就可以直接返回结果.
3.确定初始条件
因为递归会将区间不断的缩小,当左右边界相同,即区间内只有一个数了,那么就不需要查找了,直接返回即可.(逻辑为:每一次缩小区间都保证了被查找的数在区间内,当区间缩小到只有一个数,且被查找的还在区间内,那么这个数就是被查找的数了.)

源代码


import java.util.Scanner;
class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int k=sc.nextInt();
        int[] list=new int[n];
        for(int i=0;i<n;i++){
            list[i]=sc.nextInt();
        }
        System.out.print(quick_select(list,0,n-1,k));
    }
    static int quick_select(int[] list,int l,int r,int k){ //功能是选出从l到r里第k大的数

        if(l==r) return list[l];
        int i=l-1,j=r+1,x=list[(l+r)>>1];
        while(i<j){
            do i++;while(list[i]<x);
            do j--;while(list[j]>x);
            if(i<j){
                int temp=list[i];
                list[i]=list[j];
                list[j]=temp;
            }
        }
        if(j-l+1>=k){  //从l~j是一组 j+1~r是另一组
            return quick_select(list,l,j,k);

        }
        else{
            return quick_select(list,j+1,r,k-(j-l+1));

        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值