347.前k个高频元素
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2:
输入: nums = [1], k = 1 输出: [1]
提示:
1 <= nums.length <= 105 k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
思路
创建一个优先级队列 pq,它存储的是数组,用于存储元素及其对应的出现次数。队列的排序方式是按照元素的出现次数从小到大排序。
创建一个大小为 k 的结果数组 res,用于存储前 k 个高频元素。
创建一个哈希表 map,用于记录每个元素出现的次数。
遍历 nums 数组,统计每个元素出现的次数,并存储在 map 中。
遍历 map 的键值对,将键值对转化为数组 tmp,其中 tmp[0] 是元素,tmp[1] 是该元素出现的次数。
将 tmp 加入优先级队列 pq 中。
如果队列 pq 的大小超过了 k,则弹出队列中最小的元素(出现次数最少的元素)。
遍历结束后,队列 pq 中剩余的元素就是前 k 个高频元素,将它们依次存入结果数组 res。
返回结果数组 res。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
// 优先级队列,为了避免复杂 api 操作,pq 存储数组
// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从小到大,o2 - o1 反之
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
int[] res = new int[k]; // 答案数组为 k 个元素
Map<Integer, Integer> map = new HashMap<>(); // 记录元素出现次数
for(int num : nums) map.put(num, map.getOrDefault(num, 0) + 1);
for(var x : map.entrySet()) { // entrySet 获取 k-v Set 集合
// 将 kv 转化成数组
int[] tmp = new int[2];
tmp[0] = x.getKey();
tmp[1] = x.getValue();
pq.offer(tmp);
// 下面的代码是根据小根堆实现的,只保留优先队列的最后的k个,只要超出了k我就将最小的弹出,剩余的k个就是答案
if(pq.size() > k) {
//poll()和remove一样,不过poll在队列为空的时候不返回错误
pq.poll();
}
}
for(int i = 0; i < k; i ++) {
res[i] = pq.poll()[0]; // 获取优先队列里的元素
}
return res;
}
}