携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情 >>
一、题目描述 LeetCode - 347
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
二、解题思路
本题要求返回数组nums中出现频率最高的k个元素。可以考虑使用堆排序来解答,既将数组中各个元素的出现频率作为排序标准,维护一个大小为k的小顶堆,若堆中元素小于k个,则直接将当前元素加入到堆中,若堆中元素大于等于k个,则比较堆顶元素的出现频率和当前元素的出现频率,若小于当前元素的出现频率则弹出堆顶元素,并将当前元素入堆,若大于当前元素,则不改变堆。
Java中可以借助优先队列来实现小顶堆,在使用优先队列时需要定义排序规则,既重写Comparator接口的compare方法
/**
* @param o1 the first object to be compared.
* @param o2 the second object to be compared.
* @return a negative integer, zero, or a positive integer as the
* first argument is less than, equal to, or greater than the
* second.
* @throws NullPointerException if an argument is null and this
* comparator does not permit null arguments
* @throws ClassCastException if the arguments' types prevent them from
* being compared by this comparator.
*/
int compare(T o1, T o2);
由该方法的注释可知,该方法返回一个负数,0,正数分别表示第一个参数小于,等于,大于第二个参数,在实现小顶堆的compare方法时只需返回o1-o2即可。
三、代码
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<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
for (Map.Entry<Integer, Integer> entry : map.entrySet()){
int num = entry.getKey();
int count = entry.getValue();
if (queue.size() == k){
if (queue.peek()[1] < count){
queue.poll();
queue.offer(new int[]{num, count});
}
}else {
queue.offer(new int[]{num, count});
}
}
int[] res = new int[k];
for (int i=0; i<k; i++){
res[i] = queue.poll()[0];
}
return res;
}
}
四、总结
本题使用小顶堆,得出了数组中出现频率最高的k个元素,时间复杂度为O(nlogk),空间复杂度为O(n)。