Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目分析
设计一个找到数据流中第 k大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums)使用整数k和整数流nums初始化对象。int add(int val)将val插入数据流nums后,返回当前数据流中第k大的元素。
思路讲解
- 我们可以维护⼀个⼤⼩为K的⼩根堆,⽤来存储前K个最⼤的元素。
- 然后将数据流中的数据加⼊到⼩根堆中进⾏调整,返回堆顶的元素
- 每次添加一个元素的时候,就将该元素加入小根堆中,如果此时的堆大小比K大,我们就将堆顶的元素弹出。
- 小根堆的堆顶就是我们的第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
代码
/*
* @lc app=leetcode.cn id=703 lang=javascript
*
* [703] 数据流中的第 K 大元素
*/
// @lc code=start
/**
* @param {number} k: 第K大元素
* @param {number[]} nums
*/
var KthLargest = function(k, nums) {
// 通过堆每次拿最小值
this.k = k
this.heap = new MinHeap() // new一个小根堆
for (n of nums) {
this.add(n) // 遍历数组,往堆中去添加小根堆
}
};
/**
* @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)
*/
// @lc code=end