跳至主要內容

40. 最小的k个数


40. 最小的k个数open in new window

🟢   🔖  数组 分治 快速选择 排序 堆(优先队列)  🔗 力扣open in new window

题目

仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限

示例 1:

输入: stock = [2,5,7,4], cnt = 1

输出:[2]

示例 2:

输入: stock = [0,2,3,6], cnt = 2

输出:[0,2] 或 [2,0]

提示:

  • 0 <= cnt <= stock.length <= 10000
  • 0 <= stock[i] <= 10000

解题思路

思路一:sort 排序

  1. 排序:使用 sort 方法对库存数组进行升序排序,便于找到库存最少的商品。
  2. 截取最小值:取排序后数组的前 cnt 个元素,即为库存最少的商品余量。

复杂度分析

  • 时间复杂度O(n log n),主要来源于排序操作。
  • 空间复杂度O(n),JavaScript 中的排序实现使用了 O(n) 的额外空间。

思路二:快速选择算法

快速选择算法非常高效,其原理基于快速排序的分治思想,适合在不需要对整个数组进行排序时寻找第 k 小的元素。

其主要步骤如下:

  1. 选择一个枢轴:从数组中选择一个元素作为枢轴(pivot)。通常选择最后一个元素或中间的元素。

  2. 分区操作:将数组分成两部分:

    • 小于枢轴的元素
    • 大于或等于枢轴的元素
    • 通过一次遍历,将所有小于枢轴的元素移到左侧,所有大于枢轴的元素移到右侧,最后将枢轴放到它的正确位置。
  3. 判断位置

    • 如果枢轴的位置正好是我们要找的第 k 小元素的位置,返回该元素。
    • 如果 k 小于枢轴的位置,继续在左侧子数组中进行快速选择。
    • 如果 k 大于枢轴的位置,继续在右侧子数组中进行快速选择。
  4. 递归:重复上述过程,直到找到第 k 小的元素。

复杂度分析

  • 时间复杂度O(n),在平均情况下,快速选择算法的复杂度是 O(n)
  • 空间复杂度O(1),使用常量空间来进行分区操作。

思路三:桶排序

  1. 确定范围:首先确定库存的范围。找到库存数组中的最大值 maxStock

  2. 桶的创建

    • 根据库存值的范围创建桶。每个桶可以对应一个特定的库存值或一段范围。为了简化,我们可以选择每个桶表示一个库存数量。
    • 创建一个大小为 maxStock + 1 的数组 buckets,用于统计每个库存数量出现的次数。
  3. 分配元素:遍历 stock 数组,将每个库存数量在 buckets 中的相应位置加一。

  4. 提取结果:从小到大遍历 buckets,每次取出库存数量,直到收集到 cnt 个商品。

复杂度分析

  • 时间复杂度O(n + m),,其中 nstock 数组的长度,m 是库存的最大值。创建桶和遍历桶的时间复杂度较低。
  • 空间复杂度O(m),需要额外的空间存储桶。

代码

sort 排序
/**
 * @param {number[]} stock
 * @param {number} cnt
 * @return {number[]}
 */
var inventoryManagement = function (stock, cnt) {
	stock.sort((a, b) => a - b);
	return stock.slice(0, cnt);
};