JavaScript实现 - LeetCode刷题 -【前 K 个高频元素】- 第 347 题 !!!

题目:

LeetCode题目链接

题目截图:

LeetCode刷题

解题步骤:

1.构建一个最小堆,并依次把数组的值插入堆中
2.当堆的容量超过K,就删除堆顶
3.插入结束后,堆顶就是第K个最大元素,就比如只剩下三个元素了,则堆顶就是第三个最大元素

代码:

// 最小堆
class MinHeap {
  constructor() {
    this.heap = [];
  }
  // 交换
  swap(i1, i2) {
    const temp = this.heap[i1];
    this.heap[i1] = this.heap[i2];
    this.heap[i2] = temp;
  }
  // 获取父节点下标
  getParentIndex(i) {
    return (i - 1) >> 1;
  }
  // 获取左子节点下标
  getLeftIndex(i) {
    return i * 2 + 1;
  }
  // 获取右子节点下标
  getRightIndex(i) {
    return i * 2 + 2;
  }
  // 上移操作
  shiftUp(index) {
    if (index === 0) return;
    const parentIndex = this.getParentIndex(index);
    // 以下部分稍作改动
    if (this.heap[parentIndex] && this.heap[parentIndex].value > this.heap[index].value) {
      this.swap(parentIndex, index);
      this.shiftUp(parentIndex);
    }
  }
  // 下移操作
  shiftDown(index) {
    const leftIndex = this.getLeftIndex(index);
    const rightIndex = this.getRightIndex(index);
    if (this.heap[leftIndex] && this.heap[leftIndex].value < this.heap[index].value) {
      this.swap(leftIndex, index);
      this.shiftDown(leftIndex);
    }
    if (this.heap[rightIndex] && this.heap[rightIndex].value < this.heap[index].value) {
      this.swap(rightIndex, index);
      this.shiftDown(rightIndex);
    }
  }
  // 插入元素
  insert(value) {
    this.heap.push(value);
    this.shiftUp(this.heap.length - 1);
  }
  // 删除堆顶元素
  pop() {
    this.heap[0] = this.heap.pop();
    this.shiftDown(0);
  }
  // 获取堆顶元素
  peek() {
    return this.heap[0];
  }
  // 获取堆的大小
  size() {
    return this.heap.length;
  }
}
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var topKFrequent = function (nums, k) {
  // 解法一:
  // const map = new Map(); // 统计元素出现的频率
  // nums.forEach(n => {
  //   map.set(n, map.has(n) ? map.get(n) + 1 : 1);
  // });
  // console.log(map);
  // console.log(Array.from(map)); // [[1, 3], [2, 2], [3, 1]]是一个二维数组,每一项的第二个元素表示出现的次数
  // const list = Array.from(map).sort((a, b) => b[1] - a[1]);  // Array.from()里面不光可以传类数组,也可以传map和set,这样的话,new Set或者Map的时候,里面可以分别传一维数组和二维数组,sort方法可以试一下,看一下输出结果是按什么序,如果不对的话,可以颠倒一下就行,这里是按降序
  // console.log(list);
  // return list.slice(0, k).map(n => n[0]);  // 映射一下,返回一个数组
  // 上面的代码的结果是正确的,遍历的时间复杂度是O(n),sort的时间复杂度最快也是O(n logn),所以时间复杂度是O(n logn),不符合要求
  // 解法二:用到最小堆
  const map = new Map();
  nums.forEach(n => {
    map.set(n, map.has(n) ? map.get(n) + 1 : 1);  
  });
  const h = new MinHeap();
  map.forEach((value, key) => { 
    h.insert({ value, key });
    if (h.size() > k) h.pop();
  });
  return h.heap.map(obj => obj.key);
};

时间复杂度分析:

时间复杂度是O(n logk)

空间复杂度分析:

空间复杂度是O(n)

怎么样,是不是很简单,你学会了吗 ?

LeetCode刷题

LeetCode刷题

如果这篇文章能够帮助到您,希望您不要吝惜点赞👍👍和收藏💖💖,您的支持是我继续努力的动力 💪💪 !!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值