剑指offer42

234 阅读2分钟

题目描述

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

解题思路分析

  • 这道题有个很明显的方法,先排序然后直接取k个数,但是这肯定不是人家想要的答案
  • 这道题可以使用快排的思想来解答,同时也可使用堆的思想来解答
  • 使用快排的思想每次选择一个base,使得比base大的数放到base的左边,比base小的数放到base的右边,我们只要找到base的下标为k时,那么该base的左边k个数就是最小的
  • 通过堆的方法就是先使用k个数建立一个大顶堆,然后从k+1个数开始,分别判断k+1个数是否小于当前堆顶元素,小于则入堆,并重新调整堆,然后就可以很轻松的获得最小的k个数

代码实现

  • 快排思想
public ArrayList<Integer> getLeastKNumbers(int[] input, int k) {
    if (input == null || input.length <= 0 || k <= 0) {
        return null;
    }
    ArrayList<Integer> list = new ArrayList<>();
    int start = 0, end = input.length - 1;
    int i = partition(input, start, end);
    //循环找到第k + 1大的数
    while (i != k) {
        if (i > k) {
            end = i - 1;
            i = partition(input, start, end);
        } else {
            start = i + 1;
            i = partition(input, start, end);
        }
    }
    for (int j = 0; j < k; j++) {
        list.add(input[j]);
    }
    return list;
}

private int partition(int[] nums, int start, int end) {
    int base = nums[start], i = start, j = end;
    while (i < j) {
        //从后往前遍历,直到找到比base小的值
        while (i < j && nums[j] > base) {
            j--;
        }
        if (i < j) {
            nums[i] = nums[j];  
            i++;
            //从前往后遍历,直到找到比base大的值
            while (i < j && nums[i] < base) {
                i++;
            }
            if (i < j) {
                nums[j] = nums[i];
                j--;
            }
        }
    }
    nums[i] = base;
    //返回base的下标
    return i;
}
  • 堆思想
public ArrayList<integer> getLeastKNumbers(int[] input, int k) {
    if (input == null || input.length <= 0 || k <= 0) {
        return null;
    }
    ArrayList<Integer> list = new ArrayList<>();
    //使用优先级队列来实现一个大顶堆,默认时是小顶堆
    PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, (o1, o2) -> o2 - o1);
    for (int i = 0, i < k; i++) {
        //先将前k个数入堆
        maxHeap.offer(input[i]);
    }
    //然后向后遍历,碰到比堆顶小的元素就入堆
    for (int i = k; i < input.length; i++) {
        if (input[i] < maxHeap.peek()) {
            maxHeap.poll();
            maxHeap.offer(input[i]);
        }
    }
    //放入list中返回
    for (int i = 0; i < k; i++) {
        list.add(maxHeap.poll());
    }
    return list;
}