思路:使用最小堆
- 维护一个元素数目为 k 的最小堆
- 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
- 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
- 最终,堆中的 k 个元素即为前 k 个高频元素
注意:1.避免使用大根堆,因为需要把所有元素压入堆,复杂度是 nlogn,而且还浪费内存。如果是海量元素,那就挂了
2.对于 topk 问题:最大堆求topk小,最小堆求 topk 大
3.java默认使用最小堆,由于我们是根据出现次数,也就是哈希表的值来建堆,需要自己写比较器,可以使用匿名函数来写比较器
PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> map.get(a) - map.get(b));
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
// PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> map.get(a) - map.get(b));
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
for (Integer key : map.keySet()) {
if (queue.size() < k){
queue.offer(key);
}else if (map.get(key) > map.get(queue.peek())){
queue.poll();
queue.offer(key);
}
}
int[] res = new int[queue.size()];
int index = 0;
while (!queue.isEmpty()){
res[index++] = queue.poll();
}
return res;
}
}