携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
题目描述
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105k的取值范围是[1, 数组中不相同的元素的个数]- 题目数据保证答案唯一,换句话说,数组中前
k个高频元素的集合是唯一的
解题思路——桶排序
桶排序需要先知道桶的大小,也就是说第一遍遍历数组需要统计出现次数的最大值/最小值。
知道最值之后我们就初始化一个 length=maxCnt + 1 的数组用来模拟桶。
为什么是 maxCnt + 1 呢?来看看桶排序的原理。
图解桶排序
假设存在一个长度为 4 的 nums 数组:
遍历统计可得各自的出现次数:
{
1: 2,
2: 1,
3: 1
}
其中数字 1 的出现次数最多,为两次。所以初始化一个 length = 2 + 1 的数组,其中每个元素都是一个空数组。
new Array(3).fill(0).map(()=>[]) // [[],[],[]]
那么我们已经知道最大出现次数为 3,桶排序就是将元素按出现的次数丢进对应的桶里。
按出现次数丢进桶里,最后得到的二维数组:
[[],[2,3],[1]]
回到正题
那么理解了桶排序之后,这道题的思路也很明确了,创建一个对象 mp 用来计数,一个 maxCnt 用来统计最大值,得到数据后创建一个桶 buckets,遍历对象 mp,根据 value 为下标将 key 丢入对应下标的桶里。最后从后往前输出 k 个元素。
题解
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
const lens = nums.length;
let maxCnt = -Infinity;
const mp = {};
for(let i=0; i<lens; ++i) {
const k = nums[i];
mp[k]++ || (mp[k] = 1);
if(mp[k] > maxCnt) maxCnt = mp[k]
}
const buckets = new Array(maxCnt + 1).fill(0).map(()=>[]), res = [];
for(const [k, v] of Object.entries(mp)) {
buckets[v].push(k);
}
for(let i=buckets.length-1; i>=0; --i) {
let lens = buckets[i].length, index = 0;
while(index < lens) {
res.push(buckets[i][index]);
if(res.length === k) return res;
index++;
}
}
};
解题思路——hashmap + 排序
通过 hashmap + sort 的思路也是需要一个对象 mp 来统计出现的次数。
因为题目需要的是前 k 个 出现频率最高的元素。那么我们可以将这个 mp 统计次数的对象按照 value 出现次数来降序排序,最后输出前 k 个就好了。
题解
var topKFrequent = function(nums, k) {
const lens = nums.length;
const mp = {};
for(let i=0; i<lens; ++i) {
const k = nums[i];
mp[k]++ || (mp[k] = 1);
}
return Object.entries(mp).sort((a,b)=>b[1]-a[1]).slice(0, k).map(item=>item[0]);
};