无序数组中找到最小的k个数 O(N)解法 快速排序原理方法和BFPRT方法

本文介绍了在大规模无序数组中寻找最小k个数的两种方法:快速排序和BFPRT算法。快速排序平均时间复杂度为O(N),但最坏情况为O(N^2)。BFPRT利用中位数的中位数策略,确保每次能淘汰3N/10的数据,总时间复杂度为O(N)。文章通过代码解析了这两种算法的实现细节和优化策略。

最简便的方法是循环K次,依次找出最小的,第2小的,第K小的值,时间复杂度O(N*K),这种方法使用于K比较小的时候,如个位数,如果N数据量很大,K也较大,不适用。因为K大于N时,时间复杂度变成O(N^2)。

第二种是堆排序,建立一个大根堆,时间复杂度是O(NlogK),此方法博客中有写到,详见堆排序。

一、用快速排序,随机取枢轴量可以做到平均时间复杂度O(N),但是值选的不好会退化到O(N^2)

/**
 * Created by Administrator on 2018/2/4 0004.
 * 用快速排序,随机取枢轴量可以做到平均时间复杂度O(N),但是值选的不好会退化到O(N^2)
 */
public class Main {
   
   
    public static void main(String[] args) {
        //int[] arr = {6,9,1,3,1,2,2};
        int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };
        int k = 10;
        System.out.println(Arrays.toString(getMinKNums(arr, k)));

    }

    public static int[] getMinKNums(int[] arr, int k){
        int[] res = new int[k];
        getKnumsHelp(arr, 0, arr.length-1, k, res, 0);
        return res;
    }

    public static void getKnumsHelp(int[] arr, int start, int end, int k, int[] res, int index){
        if (index == k){
            return;
        }
        int x = arr[start];
        int left = start-1, right = end + 1, i = start;
        while (i < right){
            if (arr[i] < x){
                ++left;
                swap(arr, left, i);
                ++i;
            }
            else if (arr[i] > x){
                --right;
                swap(arr, right, i);
            }
            else {
                ++i;
            }

        }
        if (right - start == k){
            for (int j = 0; j < k; j++) {
                res[index + j] = arr[start + j];
            }
        }
        else if (right - start < k){
            for (int j = 0; j < right- start; j++) {
                res[index + j] = arr[start + j];
            }
            getKnumsHelp(arr, right, end, k-(right-start), res, index + right -start);
        }
        else {
            getKnumsHelp(arr, start, right-2, k, res, index);  //特别注意此处 right-1是key处,证明right-1... start的元素个数大于k,所以下标是从right-1的前面一个位置开始,如果改成right-1就是这这个例子中死循环了
        }
    }

    public static void swap(int[] arr, int i, int j){
      
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值