[路飞]_夜寻前K个高频数

517 阅读2分钟

347. 前 K 个高频元素

常规思路 哈希

比如:nums = [1,1,1,2,2,2,3,3,8,8], k = 2

通过哈希表统计数组中各个元素出现的次数;nums哈希表如下

元素1238
元素出现次数3322

上述表格中,只需要将元素出现次数降序排列获取前K个即可得到前K个高频数;

根据上述思路编辑代码如下:

const topKFrequent = (nums, k) => {
  //哈希表,保存数组元素出现次数
  const map = {}
  nums.forEach((n) => {
    map[n] = (map[n] || 0) + 1
  })
  const list = []
  //遍历数据,将元素,和原元素出现次数放在list中
  Object.keys(map).forEach((k) => {
    list.push([Number(k),map[k]])
  })
  // list排序
  list.sort((a,b)=>{
      return b[1] - a[1]
  })
  //截取前k个元素
  const result = list.slice(0,k)
  //返回答案
  return result.map(v=>v[0])
}

代码AC木有问题,但是使用sort排序,时间复杂度是O(nlogn)级别;所以还要优化一下

空间换时间

上述用到哈希表;顺着这个思路,可以再用一个桶,将元素和元素出现的次数按照表格中的规律放入桶中;

出现次数0123
元素003,81,2

如果nums = [4,5,5,9,9,9,9,7]

出现次数01234
元素04,7509

解释上述表格: 出现3次的数据有1、2;
出现2次的数据有3、8 出现1、0次的数据没有

假设结果数组为result 从右到左遍历这个桶,如果桶中某个位置有元素,将元素放在result

当result.length === k;输出答案

根据上述思路编辑代码如下:

const topKFrequent = (nums, k) => {
  const map = {}
  nums.forEach((n) => {
    map[n] = (map[n] || 0) + 1
  })

  // 先统计出现的次数,如果数据量少于k返回

  if (Object.keys(map).length <= k) {
    return Object.keys(map)
  }

  // 数据量超过k呢?

  // 找个桶,桶最长为k;
  const list = []

  //遍历数据
  Object.keys(map).forEach((k) => {
    const idx = map[k]
    list[idx] = (list[idx] || []).concat(k)
  })

  const result = []
  for (let i = list.length - 1; i >= 0; i--) {
    if (result.length === k) return result.map(Number)
    if (list[i]) {
      result.push(...list[i])
    }
  }
  //console.log('list', list)
}