题目
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2:
输入: nums = [1], k = 1 输出: [1] 提示:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 你的算法的时间复杂度必须优于 O ( n log n ) O(n \log n) O(nlogn)
, n 是数组的大小。 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。 你可以按任意顺序返回答案。
思路
优先级队列(底层基于堆实现):在队头取元素,队尾加元素,优先队列内部自动按照元素权值排列。
题目设计三块内容:
- 统计元素出现频率——>map
- 对频率排序
- 找出前k个高频元素——>小顶堆(因为是统计最大的前k个元素,所以用小根堆,小顶堆用于降序排序)
java中优先队列默认是小根堆
注意:优先队列想要实现小顶堆,要用升序定义优先队列(因为优先队列就是堆,定义小根堆就是要升序定义,才能保证根节点最小)
- 优先队列升序定义小根堆
- 小根堆用于降序排序
这是两个概念,不要弄混了
java代码如下:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int [] res = new int[k];//存最后结果
Map<Integer,Integer> map = new HashMap<>();//key为数组元素,value为对应出现次数
for(int num : nums){
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue pq = new PriorityQueue<>((x,y)-> map.get(x) - map.get(y));//虽然优先队列默认是小顶堆,但是这里需要重新定义根据频率value排序,所以需要重新定义一下,根据get(key)的值value来进行升序
for(Integer key : map.keySet()){//获取map中所有的key
pq.add(key);//加入优先队列,只需要维持k个元素的小根堆即可
if(pq.size() > k){//一旦超出k个
pq.poll();//弹出堆顶元素,优先队列内部已经定义好排序规则
}
}
int i = 0;
while(!pq.isEmpty()){//将优先队列里的k个元素填入数组
res[i++] = (int)pq.poll();
}
return res;
}
}