前k个高频元素
题目描述
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
题目分析
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
输入: nums = [1], k = 1
输出: [1]
提示:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。
思路(一)
map和数组排序方法
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
//[...new Set(array)] 一种数组去重方法
let arr = [...new Set(nums)] //nums=[1,1,1,2,2,3] arr=[1,2,3]
//统计数组中每个元素出现的次数
var map=new Map();
for(let c of nums){
if(map.has(c)){
map.set(c,map.get(c)+1)
}else{
map.set(c,1);
}
}
//根据数组中每个元素出现的次数大小对数组中的元素进行排序,取前k大
return arr.sort((a, b) => map.get(b) - map.get(a)).slice(0, k);
};
思路(二)
桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
首先使用 map 来存储频率
然后创建一个数组(有数量的桶),将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标(桶内)即可
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
let map=new Map(); //使用map统计元素key和频率value
for(let c of nums){
if(map.has(c)){
map.set(c,map.get(c)+1);
}else{
map.set(c,1);
}
}
if(map.size <= k) { //如果统计后的map小于k,直接将map中所有的元素返回
return [...map.keys()]
}
return bucketSort(map,k);
};
let bucketSort = (map, k) => {
let arr = [], res = []
map.forEach((value, key) => {
// 利用映射关系(出现频率作为下标)将数据分配到各个桶中
if(!arr[value]) { //以map中的频率value为下标,将元素key,对应映射到arr数组中(相当于按频率大小将元素从小到大排序)
arr[value] = [key]
} else {
arr[value].push(key)
}
})
for(let i=0;i<arr.length;i++){
if(arr[i]){
res.push(...arr[i]); //注意将arr[i]前面填上...arr[i]
}
}
return res.slice(res.length-k);
}