Problem: 703. 数据流中的第 K 大元素
最小堆
思路
最小堆中堆顶的元素就是这个堆里的最小值,堆的值按照从小到大排列。如果要得到“数据流中的第 K 大元素”,就需要从堆顶删除 K 个元素,此时堆顶的元素就是 “数据流中的第 K 大元素”。
因此,我们只需要将元素加入最小堆中,同时判断堆的元素个数 size 是否大于 K,如果大,则将堆里的最小值删掉。最后,返回堆顶的元素。
最小堆的实现详见:用 JavaScript 实现优先队列和堆
代码
JavaScript
/**
* @param {number} k
* @param {number[]} nums
*/
var KthLargest = function(k, nums) {
this.k = k;
this.heap = new MinHeap();
for (const x of nums) {
console.log(x)
this.add(x);
}
};
/**
* @param {number} val
* @return {number}
*/
KthLargest.prototype.add = function(val) {
this.heap.add(val);
if (this.heap.size > this.k) {
this.heap.remove();
}
return this.heap.peek();
};
class MinHeap {
constructor(comparator = (a, b) => a - b) {
this.array = [];
this.comparator = (i1, i2) => comparator(this.array[i1], this.array[i2])
}
get size() {
return this.array.length;
}
peek() {
return this.array[0];
}
swap(a, b) {
[this.array[a], this.array[b]] = [this.array[b], this.array[a]];
}
add(value) {
this.array.push(value);
this.bubbleUp();
}
bubbleUp() {
const parent = i => Math.ceil(i / 2) - 1;
let curr = this.size - 1;
while (this.size >= 0 && this.comparator(parent(curr), curr) > 0) {
this.swap(parent(curr), curr);
curr = parent(curr);
}
}
remove(index = 0) {
if (!this.size) return null;
this.swap(index, this.size - 1);
const value = this.array.pop();
this.bubbleDown();
return value;
}
bubbleDown(index = 0) {
let curr = index;
const left = i => i * 2 + 1;
const right = i => i * 2 + 2;
const getTopChild = i => (right(i) < this.size && this.comparator(left(i), right(i)) > 0 ? right(i) : left(i));
while (left(curr) < this.size && this.comparator(curr, getTopChild(curr)) > 0) {
const next = getTopChild(curr);
this.swap(curr, next);
curr = next;
}
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* var obj = new KthLargest(k, nums)
* var param_1 = obj.add(val)
*/
复杂度分析
| 时间复杂度 | 空间复杂度 |
|---|---|
O(nlogk) | O(k) |
初始化时间复杂度是 O(nlogk),其中 n 初始化时 nums 的长度。单次插入时间复杂度为: O(logk) | 需要使用优先队列存储前 k 大的元素。 |