[路飞]_js算法:leetcode 703-数据流中的第 K 大元素

135 阅读1分钟

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

问题描述: 设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。(by leetcode 703

请实现 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

思路: 用堆来维护前K大元素(小顶堆)(后附js实现堆)

/**
 * @param {number} k
 * @param {number[]} nums
 */
 var KthLargest = function(k, nums) {
    this.k = k;
    this.heap = new Heap((i,l)=>i<l);//小顶堆
    for (const x of nums) {
       this.heap.push(x);
       if(this.heap.size>this.k){
        this.heap.pop()
    }
    }
};

KthLargest.prototype.add = function(val) {
    this.heap.push(val);
    if(this.heap.size>this.k){
        this.heap.pop()
    }
    return this.heap.top
};

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

class Heap {
    constructor(cmp) {
        this.data = [];
        this.cmp = cmp;
    }
    get size() {
        return this.data.length;
    }
    get top() {
        return this.data[0];
    }
    getData() {
        return this.data;
    }
    swap(i, j) {
        [this.data[i], this.data[j]] = [this.data[j], this.data[i]];
    }
    // 向上冒泡
    up(i) {
        let index=this.data.length-1;
        while(index>0){
            let p=Math.floor((index-1)/2);
            if(p>=0&&this.cmp(this.data[index],this.data[p])){
                this.swap(index,p);
                index=p;
            }else{
                break;
            }
        }
    }
    // 下沉操作
    down(i) {
      if(this.data.length<2)return;
      let index=0,l=2*index+1,len=this.data.length;
      while(l<len){
        let r=l+1;
        if(r<len&&this.cmp(this.data[r], this.data[l]))l=r;
        if(this.cmp(this.data[index], this.data[l]))break;
        this.swap(index,l)
        index=l;
        l=index*2+1;
      }
    }
    push(item) {
      this.data.push(item);
      this.up();
    }
    //删除堆顶元素
    pop() {
        this.swap(0, this.data.length - 1);
        const res = this.data.pop();//已删除的元素(原来的堆顶元素)
        this.down();
        return res;
    }
  }