703. 数据流中的第 K 大元素

117 阅读1分钟

Problem: 703. 数据流中的第 K 大元素

image.png

最小堆

思路

最小堆中堆顶的元素就是这个堆里的最小值,堆的值按照从小到大排列。如果要得到“数据流中的第 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 大的元素。

同类题

239. 滑动窗口最大值

参考资料

数据流中的第 K 大元素