最小堆
如果将数据流中的前k大元素
存储在最小堆中,因为堆顶是最小值,所以堆顶元素就是当前数据流中的第k
大元素。
可以在之前最小堆的实现基础上扩展一下。👉 最小堆实现
之前的实现可以无限存储,这里可以定义一个最大长度
- 当堆内长度小于最大长度时,还是按照之前的逻辑加入,同时对新加入元素做
swim
调整 - 但是如果长度大于等于最大长度,就直接将堆顶元素换成新加入的元素,然后对堆顶做
sink
调整
具体代码:
const KthLargest = function(k, nums) {
this.k = k;
this.heap = new MinBinaryHeap(nums, k);
};
KthLargest.prototype.add = function(val) {
this.heap.push(val);
return this.heap.peek();
};
class MinBinaryHeap {
constructor(data, k) {
this.s = []
this.len = 0
this.k = k
// 对初始数据做 堆化
this.heapify(data)
}
heapify(data) {
for(let i = 0; i < data.length; i++) {
this.push(data[i])
}
}
push(el) {
// 将总长度限制在k范围内
if (this.len < this.k) {
this.s[this.len] = el
++this.len
if (this.len > 1) {
this.swim(this.len - 1)
}
} else {
if (this.s[0] >= el) {
return
}
this.s[0] = el
this.sink(0)
}
}
pop() {
if (this.len === 0) {
return null
}
const top = this.s[0]
if (this.len > 1) {
this.s[0] = this.s[this.len - 1]
this.sink(0)
}
this.len--
return top
}
peek() {
if (this.len === 0) {
return null
} else {
return this.s[0]
}
}
sink(idx) {
const lastIdx = this.len - 1
while (idx <= lastIdx) {
const rightIdx = (idx + 1) * 2
const leftIdx = rightIdx - 1
if (leftIdx <= lastIdx) {
let smallValueIdx = leftIdx
if (rightIdx <= lastIdx && this.compare(smallValueIdx, rightIdx) > 0) {
smallValueIdx = rightIdx
}
if (this.compare(idx, smallValueIdx) > 0) {
this.swap(idx, smallValueIdx)
idx = smallValueIdx
} else {
break
}
} else {
break
}
}
}
swim(idx) {
while (idx >= 0) {
let parent = (idx - 1) >> 1
if (this.compare(parent, idx) > 0) {
this.swap(parent, idx)
idx = parent
} else {
break
}
}
}
swap(a, b) {
let temp = this.s[a]
this.s[a] = this.s[b]
this.s[b] = temp
}
compare(a, b) {
return this.s[a] - this.s[b]
}
}
排序 + 二分
这道题还有一种思路就先将数组排序,之后二分查找新数据应该插入的位置,然后取索引为k-1
的值即为第k
大的值
const KthLargest = function (k, nums) {
this.k = k
this.sorted = nums.sort((a, b) => b - a)
}
KthLargest.prototype.add = function (val) {
let idx = this.findLessThan(val)
// 插入对应的位置
// splice对负数会反向查找
if (idx <= -1) {
this.sorted.unshift(val)
} else if (idx >= this.sorted.length) {
this.sorted.push(val)
} else {
this.sorted.splice(idx, 0, val)
}
return this.sorted[this.k - 1]
}
// 二分查找到 val 需要放入的索引
KthLargest.prototype.findLessThan = function (val) {
let left = -1,
right = this.sorted.length
while (left < right) {
let mid = left + ((right - left) >> 1)
if (this.sorted[mid] >= val) {
left = mid + 1
} else {
right = mid
}
}
return right
}