题目
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 10^5
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
思路
取大用小。
- 先用Map扫描一遍原集合,将每个元素及其出现的频率存储在Map中。
- 再次扫描Map,构建最多存储k个值的最小堆,按比较规则入队列(频率越高,值越大),将key值存入优先级队列。难点:根据出现频率大小定义优先级(给优先级队列传入比较器)(碰到类似问题,要擅长用自定义类来解决)
- 依次出队列元素即可。
代码
class Solution {
//现在需要把出现的元素和出现的次数做映射
//比较的规则是两个不同的key对应的value(出现的频次)谁大谁小
private class Freq {
//不同的元素
int key;
//出现的次数
int freq;
//构造方法
public Freq(int key, int freq) {
this.key = key;
this.freq = freq;
}
}
public int[] topKFrequent(int[] nums, int k) {
//1.先扫描原数组,将每个元素及出现的次数存储在Map中
Map<Integer, Integer> map = new HashMap<>();
for(int i : nums) {
map.put(i, map.getOrDefault(i, 0) + 1);
/**
* 此处i相当于key值(即每个元素值)value相当于每个元素出现的频次
* put(key, value);当key已经存在就更新value值
* map.getOrDefault(key, defaultValue);就是每个元素出现的频次。当key不存在时,返回默认值defaultValue;当key存在时,返回对应的value值。
* 等同于下面的代码:
* if(map.containsKey(i)) {
* int value = map.get(i); //得到每个元素出现的频次
* map.put(i, value + 1);
* } else {
* map.put(i, 1);
* }
*/
}
//2.扫描Map集合,将前k个出现频次最高的入优先级队列(最小堆)
//向优先级队列中传入一个比较器,比较的是两个Freq对象的value值谁大谁小 o1 - o2
PriorityQueue<Freq> queue = new PriorityQueue<>(new Comparator<Freq>() {
@Override
public int compare(Freq o1, Freq o2) {
return o1.freq - o2.freq;
}
});
/**
* Map集合的遍历
* 每个entry存储了出现的元素(key)以及出现的次数(value)
* 哈希表类entrySet方法
* 在java.util包中可用
* 用于返回哈希表的存在的一组条目
* 是一个非静态方法,只能通过类对象访问,如果常使用类名称访问该方法,则会收到错误信息
* 在返回条目集时不会引发异常
* 它不接受任何参数
*/
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if(queue.size() < k) {
queue.offer(new Freq(entry.getKey(), entry.getValue()));
} else {
//当前entry.value > 堆顶元素才出队
Freq peekFreq = queue.peek();
if(entry.getValue() > peekFreq.freq) {
//出队,更新为频次更大的元素入队
queue.poll();
queue.offer(new Freq(entry.getKey(), entry.getValue()));
}
}
}
//3.依次出队列元素
int[] ret = new int[k];
for (int i = 0; i < k; i++) {
ret[i] = queue.poll().key;
}
return ret;
}
}
该问题通过使用HashMap存储元素频率,然后利用优先级队列(最小堆)按频率降序获取前k个高频元素。关键在于自定义比较器以频率为优先级,并在队列满时进行比较和更新。
490

被折叠的 条评论
为什么被折叠?



