面试题40_最小的k个数

题目描述

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

题解一

最直观的解法就是对数组进行排序,然后输出前k个数。

时间复杂度为O(nlogn),空间复杂度为O(1)。

public ArrayList GetLeastNumbers_Solution(int[] input, int k) {
    ArrayList res = new ArrayList<>();
    if (k > input.length)
        return res;
    Arrays.sort(input);
    for (int i = 0; i < k; i++)
        res.add(input[i]);
    return res;
}

题解二

和上一题类似,也可以利用快排的思想。当pivot的数组下标为k时,pivot左边的k个数字都小于pivot,pivot右边的n-k个数字都大于或等于pivot。若找到这与的pivot,直接输出数组的前k个元素即可。

时间复杂度为O(n),空间复杂度为O(1)。

public ArrayList GetLeastNumbers_Solution2(int[] input, int k) {
    ArrayList res = new ArrayList<>();
    if (k > input.length || input.length == 0)
        return res;
    int pivotPos = Partition(input, 0, input.length-1);
    while (k < input.length && pivotPos != k) {
        if (pivotPos > k)
            pivotPos = Partition(input, 0, pivotPos-1);
        else pivotPos = Partition(input, pivotPos+1, input.length-1);
    }
    for (int i = 0; i < k; i++)
        res.add(input[i]);
    return res;
}

private int Partition(int[] array, int left, int right) {
    int pivot = array[left];
    while (left < right) {
        while (left < right && array[right] >= pivot) right--;
        array[left] = array[right];
        while (left < right && array[left] <= pivot) left++;
        array[right] = array[left];
    }
    array[left] = pivot;
    return left;
}

题解三

利用最大堆的思想,维护一个大小为k的最大堆,用于存储这最小的k个数。

遍历input,与最大堆中的最大值进行比较。当输入的数字比这k个数中的最大值还小时,则用输入的数字替换这k个数中的最大值。

尽管这种算法的时间复杂度为O(nlogn),比题解二慢一些,但它有两个优点:

  1. 没有修改输入数组的顺序。(所有操作都是在最大堆中完成的)
  2. 适合海量输入数据。(尤其是当输入数组很大而k很小时,这时候只需要维护一个大小为k的最大堆即可)

时间复杂度为O(nlogn),空间复杂度为O(1)。

public ArrayList GetLeastNumbers_Solution3(int[] input, int k) {
    ArrayList res = new ArrayList<>();
    if (k <= 0 || k > input.length)
        return res;

    // 构建最大堆
    PriorityQueue maxHeap = new PriorityQueue<>(k, new Comparator() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2.compareTo(o1);
        }
    });

    // 遍历input, 并与最大堆中的最大值进行比较
    for (int num : input) {
        if (maxHeap.size() < k)
            maxHeap.offer(num);
        else if (!maxHeap.isEmpty() && maxHeap.peek() > num) {
            maxHeap.poll();
            maxHeap.offer(num);
        }
    }
    res.addAll(maxHeap);
    return res;
}

你可能感兴趣的:(面试题40_最小的k个数)