思路:先循环整个数组,将数组中的元素和元素出现的次数存hashmap的集合中,在循环集合,建立一个有优先队列PriorityQueue,优先队列的长度为k,当长度还未到达k的时候直接将数据放入优先队列中,优先队列长度为k时,比较优先队列顶部的元素大小,当元素大于队列顶部元素时,取出顶部元素并将当前元素放入队列中。
优先队列(PriorityQueue):具体是通过完成二叉树实现,小顶堆保证每个节点的值都小于等于其两个子节点,顶部则是最小值,大顶堆则相反。本题使用的是大顶堆,需要重写比较器Comparator。
代码如下:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int[] res = new int[k];
Map<Integer, Integer> numsMap = new HashMap<>(nums.length);
//遍历数组将数组,出去重复字段,并且将元素及元素出现的次数存入hashmap集合中
for(int i : nums) {
Integer num = numsMap.getOrDefault(i, 0);
numsMap.put(i, ++num);
}
//优先队列需要重现比较器。这里重写了比较器实现了大顶堆
PriorityQueue<Map<Integer, Integer>> priorityQueue = new PriorityQueue<>(new Comparator<Map<Integer, Integer>>() {
@Override
public int compare(Map<Integer, Integer> o1, Map<Integer, Integer> o2) {
return o1.get("val") - o2.get("val");
}
});
//lamda表达式,我在力扣提交代码的时候报错了,上面那段代码没问题,可能是力扣不支持。
/*PriorityQueue<Map<Integer, Integer>> priorityQueue = new PriorityQueue<Map<Integer, Integer>>(((o1, o2) -> {
return o1.get("val") - o2.get("val");
}));*/
//循环hashmap集合
for(Map.Entry<Integer, Integer> e : numsMap.entrySet()) {
int key = e.getKey();
int val = e.getValue();
//当队列元素不足k时,直接放入队列中
if(priorityQueue.size() < k) {
priorityQueue.add(new HashMap(2) {
{
put("key", key);
put("val", val);
}
});
} else {
//当队列已经满员,则先比较顶部元素和当前元素的大小,如果顶部元素小于当前元素则将顶部元素取出,然后放入当前元素
if(priorityQueue.peek().get("val") < val ) {
priorityQueue.poll();
priorityQueue.add(new HashMap(2) {
{
put("key", key);
put("val", val);
}
});
}
}
}
//循环优先队列,将队列中的元素放入返回值中
for(int i = 0; !priorityQueue.isEmpty(); i++) {
res[i] = priorityQueue.poll().get("key");
}
return res;
}
}