剑指Offer-题40(Java版):最小的k个数

参考自:《剑指Offer——名企面试官精讲典型编程题》

题目:最小的k个数
输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

主要思路:使用最大堆,保存目前已知的最小的k个数,堆顶是k个数中最大的元素。遍历数组,若堆中元素个数小于k,则直接添加到当前数字到堆中;若当前数字小于堆顶元素(即堆中最大元素),说明堆顶元素不可能是最小的k个数之一,因此用当前数字替换掉堆顶元素,然后保持堆有序(即最大元素在堆顶);若当前数字大于堆顶元素,说明当前数字不可能是最小的k个数之一,跳过该数字。

Java最大堆API:可使用优先队列来实现最大堆(设置比较器为逆序( Queue < < <Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
))

扩展:使用最大堆(或最小堆)查找最小(或最大)的k个数,比较适合处理海量数据。因为内存的限制,通常不能一次全部载入所有输入数据到内存中。因此,可以每次只读取一部分数据,使用堆来维持目前已知的状态。

关键点:最大堆,最小堆,前k个数

时间复杂度:O(nlog(k)),维持堆有序需要O(log(k))

public class LeastNumbersOfK {
    public static void main(String[] args) {
        int[] input = {4, 5, 1, 6, 2, 7, 3, 8};
        int k = 4;
        List<Integer> result = getKthLeastNumbers(input, k);
        System.out.println(result);
    }

    private static List<Integer> getKthLeastNumbers(int[] input, int k) {
        if (input == null) {
            return new ArrayList<>();
        }
        int length = input.length;
        if (length == 0 || k <= 0 || k > length) {
            return new ArrayList<>();
        }
        //最大堆
        Queue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
        for (int currentValue : input) {
            if (maxHeap.size() < k) {
                maxHeap.add(currentValue);
            } else {
                //当前值比最大堆中的最大值小,则用当前值替换最大值
                if (currentValue < maxHeap.peek()) {
                    //移除最大值
                    maxHeap.poll();
                    //添加当前值
                    maxHeap.add(currentValue);
                }
            }
        }
        return new ArrayList<>(maxHeap);
    }
}

你可能感兴趣的:(剑指Offer-Java)