这是 LeetCode 上 2021-9-3 的每日一题:「面试题 17.14. 最小K个数」
1. 题目描述
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
2. 解答
1. 排序
排序 + 返回前
k
个数。
const smallestK = (arr, k) => {
arr.sort((a, b) => a - b);
arr.length = k;
return arr;
};
2. 堆排序
将数组
arr
的数放入最小堆中,返回堆中前k
个数。
// 默认最大堆
const defaultCmp = (x, y) => x > y;
// 交换元素
const swap = (arr, i, j) => ([arr[i], arr[j]] = [arr[j], arr[i]]);
// 堆类,默认最大堆
class Heap {
constructor(cmp = defaultCmp) {
this.container = [];
this.cmp = cmp;
}
// 插入
insert(data) {
const { container, cmp } = this;
container.push(data);
let index = this.size() - 1;
while (index) {
let parent = (index - 1) >> 1;
if (!cmp(container[index], container[parent])) {
return;
}
swap(container, index, parent);
index = parent;
}
}
// 弹出堆顶,并返回
pop() {
const { container, cmp } = this;
if (!this.size()) {
return null;
}
swap(container, 0, this.size() - 1);
const res = container.pop();
const length = this.size();
let index = 0,
exchange = index * 2 + 1;
while (exchange < length) {
// // 以最大堆的情况来说:如果有右节点,并且右节点的值大于左节点的值
let right = index * 2 + 2;
if (right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
if (!cmp(container[exchange], container[index])) {
break;
}
swap(container, exchange, index);
index = exchange;
exchange = index * 2 + 1;
}
return res;
}
// 获取堆大小
size() {
return this.container.length;
}
// 获取堆顶
peek() {
if (this.size()) return this.container[0];
return null;
}
}
const smallestK = (arr, k) => {
const minHeap = new Heap((x, y) => x < y);
for (const num of arr) {
minHeap.insert(num);
}
const res = [];
for (let i = 0; i < k; i++) {
res.push(minHeap.pop());
}
return res;
};
😄最近新创建了个开源仓库,总结LeetCode的每日一题,目前已有C++、JavaScript语言版本,欢迎大家提供其他语言版本!
🖥️仓库地址:「每日一题系列」