LeetCode算法学习之--Heap--最小的k个数

1,284 阅读2分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

大家好今天给大家分享下一道 LeetCode 简单难度 的题目[剑指 Offer 40. 最小的k个数](leetcode-cn.com/problems/gr…)

题目

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

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

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


分析

1.整数数组

2.有重复值

3.有负数

4.输出最小的k个数的数组

解法

1.sort

2.maxHeap

解法一:sort

思路
1.排序后单向递增
2.取最小的前k个数
*/

var getLeastNumbers = function (arr, k) {
  return arr.sort((a, b) => a - b).slice(0, k);
};

/* 复杂度
时间 O(logn)
空间 O(logn)
*/

解法二:maxHeap

思路
1.书写最大堆栈的类
2.利用最大堆栈存入所有的元素
3.取出arr.len-k个元素
4.返回 剩下的元素就是最小的元素
*/

// maxHeap的写法借鉴 https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/chao-quan-3chong-jie-fa-zhi-jie-pai-xu-zui-da-dui-/

// 交换元素
function swap(arr, i, j) {
  const temp = arr[j];
  arr[j] = arr[i];
  arr[i] = temp;
}

class MaxHeap {
  constructor(arr) {
    this.array = [];
    if (Array.isArray(arr)) {
      // 把输入的arr 变成最大堆的方式
      for (const item of arr) {
        this.insert(item);
      }
    }
  }

  // 插入
  insert(item) {
    // 先把元素放入最后面
    this.array.push(item);
    let index = this.array.length - 1;
    // 维护maxHeap的结构,向上比较 最终保证,父级一定大于子级
    this.heapifyUp(index);
  }

  heapifyUp(index) {
    // 不断的比较父类,最终形成一个最大堆的树形结构
    while (index) {
      // 求出父类的索引 Math.floor((index-1)/2)
      let parentIndex = Math.floor((index - 1) / 2);
      const child = this.array[index];
      const parent = this.array[parentIndex];
      // 比较父类的元素,如果比父类大则和父类交换位置
      if (child > parent) {
        swap(this.array, index, parentIndex);
        index = parentIndex;
      } else {
        break;
      }
    }
  }

  // 删除的方法
  extract() {
    if (!this.array.length) return null;
    // 把maxHeap的根部元素和后面的元素想替换
    swap(this.array, 0, this.array.length - 1);
    const res = this.array.pop();
    const index = 0;
    // 维护maxHeap的结构,向下比较 最终保证,父级一定大于子级
    this.heapifyDown(index);
    return res;
  }

  heapifyDown(index) {
    const length = this.array.length;

    //求出根部的左子元素
    let exchange = 2 * index + 1; // 左边

    //不断和子元素比较,最终达到 根部元素最大
    while (exchange < length) {
      const right = 2 * index + 2;
      // 如果右边的元素比较大,则把元素替换成右边的元素 然后比较,反正保持替换后父级一定大于子级的元素
      if (right < length && this.array[exchange] < this.array[right]) {
        exchange = right;
      }

      if (this.array[exchange] <= this.array[index]) {
        break;
      }

      swap(this.array, exchange, index);
      index = exchange;
      exchange = index * 2 + 1;
    }
  }

  top() {
    if (this.array.length) return this.array[0];
    return null;
  }
}
var getLeastNumbers = function (arr, k) {
  // 把所有元素都入heap
  const maxHeap = new MaxHeap(arr);
  //取出arr.length-k
  for (let i = 0; i < arr.length - k; i++) {
    maxHeap.extract();
  }

  // 剩下的就是最小的k个数
  return maxHeap.array;
};

/* 复杂度
时间 O(nLogn)
空间 O(n)
*/

总结

这道题考察的对maxHeap的应用,利用maxHeap中根为最大值的特性来求解,另外使用sort也是很常见的一种取最小值区间的一个方法

大家可以看看我分享的一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能够帮到大家,我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢

大家如果对“TS”感兴趣的可以看看我的专栏 (TypeScript常用知识),感谢大家的支持

文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com