【路飞】算法与数据结构-数据流中的第 K 大元素

472 阅读1分钟

不管全世界所有人怎么说,我都认为自己的感受才是正确的。无论别人怎么看,我绝不打乱自己的节奏。喜欢的事自然可以坚持,不喜欢的怎么也长久不了。

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];
};