不管全世界所有人怎么说,我都认为自己的感受才是正确的。无论别人怎么看,我绝不打乱自己的节奏。喜欢的事自然可以坚持,不喜欢的怎么也长久不了。
LeetCode:原题地址
题目要求
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。 int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
示例 :
输入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:
[null, 4, 5, 5, 8, 8]
解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8
提示:
- 1 <= k <= 104
- 0 <= nums.length <= 104
- -104 <= nums[i] <= 104
- -104 <= val <= 104
- 最多调用 add 方法 104 次
- 题目数据保证,在查找第 k 大元素时,数组中至少有 k 个元素
思路
这道题数组是变化的,会有数加进来,但我们始终关心前 k 大的数,所以维护一个最小堆来保存前 k 大的数字。
维护一个的 heap 数组。
当 heap 数组长度不够 k 时,新数从数组末尾推入,执行“上浮”,交换到它合适的位置。 当 heap 数组长度够 k 时,如果新数字比栈顶大,用它替换堆顶,执行“下沉”,交换到合适的位置。 最后 heap 数组存的是前 k 大的数字,堆顶是第 k 大的数字,是最小堆里最小的元素。
代码
class MinHeap {
constructor(k, nums) {
this.heap = [];
this.k = k;
}
add(num) {
if (this.heap.length < this.k) {
this.heap.push(num);
this.up(this.heap.length - 1);
} else if (num > this.heap[0]) {
this.heap[0] = num;
this.down(0);
}
}
up(i) {
while (i > 0) {
const parent = (i - 1) >> 1;
if (this.heap[parent] > this.heap[i]) {
[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];
i = parent;
} else {
break;
}
}
}
down(i) {
while (2 * i + 1 < this.heap.length) {
let child = 2 * i + 1;
if (child + 1 < this.heap.length && this.heap[child + 1] < this.heap[child]) {
child++;
}
if (this.heap[i] > this.heap[child]) {
[this.heap[child], this.heap[i]] = [this.heap[i], this.heap[child]];
i = child;
} else {
break;
}
}
}
}
var KthLargest = function (k, nums) {
this.heap = new MinHeap(k, nums);
for (let i = 0; i < nums.length; i++) {
this.heap.add(nums[i]);
}
};
KthLargest.prototype.add = function (val) {
this.heap.add(val);
return this.heap.heap[0];
};