[路飞]_LeetCode_面试题 17.14. 最小K个数

737 阅读1分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

题目

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]

提示:

0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))

来源:力扣(LeetCode)leetcode-cn.com/problems/sm…

解题思路 - 排序

最简单的方式是使用 JavaScript 内置的排序方法按升序排序,排序后取前 k 个数,就是我们要的结果。

代码实现

var smallestK = function(arr, k) {
    //将原数组拷贝一份
    const ans = [...arr]
    
    //通过数组 sort 方法进行排序,然后用 slice 方法截取前 k 个元素
    return arr.sort((a, b) => a - b).slice(0, k)
};

解题思路 - 大顶堆

另一种方式是使用大顶堆,维护一个 k 个元素的大顶堆(小顶堆也可以,只是比较的方式不一样)。

循环遍历数组中的元素:

  • 当大顶堆中的元素个数小于 k 时:将当前元素入队列;
  • 当大顶堆中的元素个数等于 k 时:如果当前元素小于堆顶元素,则把堆顶元素出队列,把当前元素入队列;
  • 循环结束后大顶堆中就是最小 k 个数;

相比排序,大顶堆的时间复杂度相对稳定,好的情况和坏的情况都是 O(nlogn)。

代码实现

var smallestK = function(arr, k) {
    if (k === 0) return []
    //初始化一个最大优先队列
    const maxQueue = new MaxPriorityQueue()

    arr.forEach(num => {
        if (maxQueue.size() < k) {
            //当队列里元素个数小于 k 个时,当前元素入队列
            maxQueue.enqueue(num)
        } else if (num < maxQueue.front()['priority']) {
            //当队列里已经有了 k 个元素时
            //并且当前元素小于队列中最大的元素时(大顶堆的堆顶)
            //把最大元素出队列
            maxQueue.dequeue()
            
            //然后把当前元素入队列
            maxQueue.enqueue(num)
        }
    })

    //最后把最大优先队列转换成数组返回
    return maxQueue.toArray().map(item => item.element)
};

如有错误欢迎指出,欢迎一起讨论!