[路飞]_js算法:leetcode 剑指 Offer 40-最小的k个数

119 阅读1分钟

最小的k个数

问题描述: 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。(by leetcode 剑指 Offer 40)

示例 1:

输入: arr = [3,2,1], k = 2
输出: [1,2] 或者 [2,1]

示例 2:

输入: arr = [0,1,2,1], k = 1
输出: [0]

思路: 用堆的数据结构来实现,维护前k小个元素 因此用大顶堆

实现一个堆

 // 堆的实现 js 
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;
    }
  }

题解:

/**
 * @param {number[]} arr
 * @param {number} k
 * @return {number[]}
 */
var getLeastNumbers = function(arr, k) {
    let heap=new Heap((i,l)=>i>l);//大顶堆
    for(let i=0;i<arr.length;i++){
        heap.push(arr[i]);
        if(heap.size>k){
            heap.pop()
        }
    }
    return heap.getData()
};