首页 > 技术文章 > 剑指 Offer 40. 最小的k个数 + 优先队列 + 堆 + 快速排序

GarrettWale 2021-02-07 22:03 原文

剑指 Offer 40. 最小的k个数

Offer_40

题目描述

解法一:排序后取前k个数

/**
 * 题目描述:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
 */
/**
 * 方法一:先对数字进行排序,然后依次找到最小的k个数
 */
public class Offer_40 {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(arr == null || arr.length == 0 || k==0)
            return new int[0];
        Arrays.sort(arr);
        int[] result = new int[k];
        int index = 1;
        result[0] = arr[0];
        for(int i = 1; i<arr.length; i++){
            if(index >= k)
                break;
            if(arr[i] != arr[i-1]){
                result[index++] = arr[i];
            }
        }
        return result;
    }
}

解法二:使用大根堆维护k个最小的数

/**

 * 方法二:使用大根堆维护k个最小的数
 */
class Offer_40_1 {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(arr == null || arr.length == 0 || k==0)
            return new int[0];
        int[] result = new int[k];
        //java的优先队列默认是小根堆实现,而c++中默认是大根堆实现。
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            //自定义排序器,降序排序
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        for(int i = 0;i<k; i++){
            priorityQueue.offer(arr[i]);
        }
        for(int i=k; i<arr.length; i++){
            if(priorityQueue.peek() > arr[i]){
                priorityQueue.poll();
                priorityQueue.offer(arr[i]);
            }
        }
        for(int i=0;i<k;i++){
            result[i] = priorityQueue.poll();
        }
        return result;
    }
}

解法三:使用快速排序的思想找前k个最小的数

/**
 * 方法三:使用快排的思想
 */
class Offer_40_2 {
    /**
     * 一趟排序,每一趟返回一个数的确定位置
     * @param arr
     * @param l
     * @param r
     * @return
     */
    int partition(int[] arr, int l, int r){
        int fix = arr[l];//需要确定arr[l]的位置
        while(l<r){
            while(arr[r] >= fix && l<r)
                r--;
            if(l<r){
                arr[l] = arr[r];
                l++;
            }
            while(arr[l] <= fix && l<r)
                l++;
            if(l<r){
                arr[r] = arr[l];
                r--;
            }
        }
        //最后才确定fix的位置
        arr[l] = fix;
        return l;
    }

    /**
     * 查找最小的k个数
     * @param arr
     * @param k
     * @param l
     * @param r
     */
    int[] quickSort(int[] arr, int k, int l, int r){
        int index = partition(arr, l, r);
        if(index == k-1){
            int[] result = new int[k];
            result = Arrays.copyOf(arr, k);
            return result;
        }else if(index <k-1){//找到的index个数小于k个,需要继续往右半部分递归查找
            return quickSort(arr, k, index+1, r);
        }else{
            return quickSort(arr, k, l, index-1);
        }
    }

    public int[] getLeastNumbers(int[] arr, int k) {
        if(arr == null || arr.length == 0 || k==0)
            return new int[0];
        return quickSort(arr, k, 0, arr.length -1);
    }
}

推荐阅读