LeetCode算法学习之--Heap--出现频率最高的 k 个数字

509 阅读2分钟

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

大家好今天给大家分享下一道 LeetCode 中等难度 的题目[剑指 Offer II 060. 出现频率最高的 k 个数字]

题目

给定一个整数数组 nums 和一个整数 k ,请返回其中出现频率前 k 高的元素。可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]

分析

1.整数数组

2.可能有重复的元素

3.k为整数小于数组长度

4.返回频率前k高的数组

解法

1.hashmap+sort

2.maxheap

*/

解法一:hashmap+sort

思路
1.创建一个对象来存储频次
2.然后给频次排序
3.输出前k个元素
*/

var topKFrequent = function (nums, k) {
  const map = {};
  for (const item of nums) {
    map[item] ? (map[item] = map[item] + 1) : (map[item] = 1);
  }

  const arr = [];
  Object.keys(map).forEach((key) => {
    arr.push({ key: key, value: map[key] });
  });

  //   排序单调减
  arr.sort((a, b) => {
    return a.value - b.value;
  });

  const res = [];
  for (let i = 0; i < arr.length; i++) {
    if (i >= arr.length - k) {
      res.push(arr[i].key);
    }
  }

  return res;
};

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

解法二:maxheap

思路
1.自定义maxHeap类,保持根元素最大
2.使用堆来取前k个根元素
*/

function swap(arr, i, j) {
  [arr[i], arr[j]] = [arr[j], arr[i]];
}

class MaxHeapObj {
  constructor(arr) {
    this.array = [];
    // 判断必须是数组
    if (Array.isArray(arr)) {
      for (const item of arr) {
        this.insert(item);
      }
    }
  }

  insert(item) {
    this.array.push(item);
    let index = this.array.length - 1;

    // 当插入的时候保持父级大于子级
    while (index) {
      const parentIndex = Math.floor((index - 1) / 2);
      if (this.array[index].value < this.array[parentIndex].value) {
        break;
      }
      swap(this.array, index, parentIndex);
      index = parentIndex;
    }
  }

  poll() {
    if (!this.array.length) return null;
    swap(this.array, 0, this.array.length - 1);
    const res = this.array.pop();

    //   删除最大值的时候一直向下轮换保持父级大于子级元素
    let index = 0;
    let compareIndex = index * 2 + 1;
    while (compareIndex < this.array.length) {
      const right = index * 2 + 2;
      if (
        right < this.array.length &&
        this.array[right].value > this.array[compareIndex].value
      ) {
        compareIndex = right;
      }

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

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

    return res;
  }
}

var topKFrequent = function (nums, k) {
  if (k === 0 || nums.length === 0) {
    return [];
  }
  //   使用map统计频次
  const map = {};
  for (const item of nums) {
    map[item] ? (map[item] = map[item] + 1) : (map[item] = 1);
  }

  //   使用arr来存储频次的对象数组
  const arr = [];
  Object.keys(map).forEach((key) => {
    arr.push({ key: key, value: map[key] });
  });

  //   把数组放入maxHeap中保持根本最大
  const maxHeapObj = new MaxHeapObj(arr);

  //   取出最大的前K个最大频次的元素
  const res = [];
  for (let i = 0; i < k; i++) {
    res.push(maxHeapObj.poll());
  }

  //   因为返回的是对象 所以需要利用array.map 处理下
  return res.map((item) => item.value);
};

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

总结

这道题考察的也是maxHeap求解前k个最高频次是元素,只是需要稍微改造下就maxHeap类就OK,还有就是利用sort+hashMap来求解(内容和这道题基本相似 juejin.cn/post/700073…

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

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

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