给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
题解
在这里,我们可以利用堆的思想:建立一个小顶堆,然后遍历「出现次数数组」:
如果堆的元素个数小于 k,就可以直接插入堆中。
如果堆的元素个数等于 k,则检查堆顶与当前出现次数的大小。如果堆顶更大,说明至少有 k 个数字的出现次数比当前值大,故舍弃当前值;否则,就弹出堆顶,并将当前值插入堆中。
遍历完成后,堆中的元素就代表了「出现次数数组」中前 k 大的值。
/*
借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
维护一个元素数目为 k 的最小堆
每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
最终,堆中的 k 个元素即为前 k 个高频元素
作者:程序员吴师兄
链接:https://leetcode.cn/problems/top-k-frequent-elements/solutions/11201/leetcode-di-347-hao-wen-ti-qian-k-ge-gao-pin-yuan-/
*/
//remove()、add()、peek()、size()
class Solution {
public int[] topKFrequent(int[] nums, int k) {
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap();
for(int num : nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//堆的构造函数
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>(){
@Override
//注意这里是Integer而不是int
public int compare(Integer a,Integer b){
return map.get(a)-map.get(b);
}
});
// 遍历map,用最小堆保存频率最大的k个元素
for(Integer key:map.keySet()){
//还未形成堆
if(pq.size()<k){
pq.add(key);
}else{
if(map.get(pq.peek())<map.get(key)){
pq.remove();
pq.add(key);
}
}
}
// 取出最小堆中的元素
int res[] = new int[k];
int i=0;
while(!pq.isEmpty()){
res[i++]=pq.remove();
}
return res;
}
}