Skip to main content

数据流中的第-k-大元素

Tips

题目类型: TopK

题目

设计一个找到数据流中第 k 大元素的类. 注意是排序后的第 k 大元素, 不是第 k 个不同的元素.

请实现 KthLargest 类:

  • KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象.
  • int add(int val)val 插入数据流 nums 后, 返回当前数据流中第 k 大的元素.
示例
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

题解

主要就是实现优先队列. 我们可以使用一个大小为 k 的优先队列来存储前 k 大的元素, 其中优先队列的队头为队列中最小的元素, 也就是第 k 大的元素.

在单次插入的操作中, 我们首先将元素 val 加入到优先队列中. 如果此时优先队列的大小大于 k, 我们需要将优先队列的队头元素弹出, 以保证优先队列的大小为 k.

/**
* @param {number} k
* @param {number[]} nums
*/
var KthLargest = function (k, nums) {
this.k = k
this.heap = new MinHeap()
for (const x of nums) {
this.add(x)
}
}

/**
* @param {number} val
* @return {number}
*/
KthLargest.prototype.add = function (val) {
this.heap.offer(val)
if (this.heap.size() > this.k) {
this.heap.poll()
}
return this.heap.peek()
}

class MinHeap {
constructor(data = []) {
this.data = data
this.comparator = (a, b) => a - b
this.heapify()
}

heapify() {
if (this.size() < 2) return
for (let i = 1; i < this.size(); i++) {
this.bubbleUp(i)
}
}

peek() {
if (this.size() === 0) return null
return this.data[0]
}

offer(value) {
this.data.push(value)
this.bubbleUp(this.size() - 1)
}

poll() {
if (this.size() === 0) {
return null
}
const result = this.data[0]
const last = this.data.pop()
if (this.size() !== 0) {
this.data[0] = last
this.bubbleDown(0)
}
return result
}

bubbleUp(index) {
while (index > 0) {
const parentIndex = (index - 1) >> 1
if (this.comparator(this.data[index], this.data[parentIndex]) < 0) {
this.swap(index, parentIndex)
index = parentIndex
} else {
break
}
}
}

bubbleDown(index) {
const lastIndex = this.size() - 1
while (true) {
const leftIndex = index * 2 + 1
const rightIndex = index * 2 + 2
let findIndex = index
if (
leftIndex <= lastIndex &&
this.comparator(this.data[leftIndex], this.data[findIndex]) < 0
) {
findIndex = leftIndex
}
if (
rightIndex <= lastIndex &&
this.comparator(this.data[rightIndex], this.data[findIndex]) < 0
) {
findIndex = rightIndex
}
if (index !== findIndex) {
this.swap(index, findIndex)
index = findIndex
} else {
break
}
}
}

swap(index1, index2) {
;[this.data[index1], this.data[index2]] = [
this.data[index2],
this.data[index1],
]
}

size() {
return this.data.length
}
}

/**
* Your KthLargest object will be instantiated and called as such:
* var obj = new KthLargest(k, nums)
* var param_1 = obj.add(val)
*/