剑指 Offer 40. 最小的k个数 | 算法

100 阅读1分钟

剑指 Offer 40. 最小的k个数

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

 

示例 1:

输入: arr = [3,2,1], k = 2
输出: [1,2] 或者 [2,1]

示例 2:

输入: arr = [0,1,2,1], k = 1
输出: [0]

 

限制:

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000

基于快速排序的 partition

回顾快速排序中的 partition 操作,可以将元素arr[0]放入排序后的正确位置,并且返回这个位置index。利用 partition 的特点,算法流程如下:

如果index = k,说明第 k 个元素已经放入正确位置,返回前 k 个元素 如果k < index,前 k 个元素在[left, index - 1]之间,缩小查找范围,继续查找 如果index < k,前 k 个元素在[index + 1, right] 之间,缩小查找范围,继续查找 为了方便理解,可以使用2, 8, 1, 1, 0, 11, -1, 0这个例子在纸上画一下过程。


var getLeastNumbers = function(arr, k) {
    const length = arr.length;
    if (k >= length) return arr;
    let left = 0,
        right = length - 1;
    let index = partition(arr, left, right);
    while (index !== k) {
        if (index < k) {
            left = index + 1;
            index = partition(arr, left, right);
        } else if (index > k) {
            right = index - 1;
            index = partition(arr, left, right);
        }
    }

    return arr.slice(0, k);
};
function partition(arr, start, end) {
    const k = arr[start];
    let left = start + 1,
        right = end;
    while (1) {
        while (left <= end && arr[left] <= k) ++left;
        while (right >= start + 1 && arr[right] >= k) --right;

        if (left >= right) {
            break;
        }

        [arr[left], arr[right]] = [arr[right], arr[left]];
        ++left;
        --right;
    }
    [arr[right], arr[start]] = [arr[start], arr[right]];
    return right;
}

方法二:


var getLeastNumbers = function(arr, k) {
    arr.sort((a,b)=>a-b)
    return arr.slice(0, k)
};