347. 前 K 个高频元素
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
输入: nums = [1], k = 1 输出: [1]
分析:
代码随想录中的解题思路:
这道题目主要涉及到如下三块内容:
- 要统计元素出现频率
- 对频率排序
- 找出前K个高频元素
首先统计元素出现的频率,这一类的问题可以使用map来进行统计。
然后是对频率进行排序,这里我们可以使用一种 容器适配器就是优先级队列。
什么是优先级队列呢?
其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。
本题的解法:
class Solution {
//先将元素加入到hashmap集合中;
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i=0;i< nums.length;i++){
//getOrDefault默认当前的key是0;
hashMap.put(nums[i], hashMap.getOrDefault(nums[i],0)+1);
}
//新建一个优先级队列,小根堆;将键值对加入到优先级队列中;
//存储的是一个数组,里面放(key,value)
//(pair1,pair2)->pair1[1]-pair2[1] 定义的比较器;默认是升序排列的;下面的有比较器的举例;
PriorityQueue<int[]> que = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]); //加入的是键值对;
for (Map.Entry<Integer,Integer> entry:hashMap.entrySet()) {
//遍历hashmap的键值对;
if (que.size() < k){
//这里加入的是一个二元组,第一个数是key,第二个数是value
que.add(new int[] {entry.getKey(),entry.getValue()});
}else{
if (entry.getValue() > que.peek()[1]){
//如果要加入的value 大于队头的value就先删除队头;再键入;
que.poll();
que.add(new int[]{entry.getKey(),entry.getValue()});
}
}
}
int[] res = new int[k];
for (int i=res.length-1;i>=0;i--){
//将key倒叙加入到res数组中,因为队头的元素都是出现频率小的元素,
//因为实现的小根堆,所以说后面出队的都是出现频率比较大的数;
res[i]=que.poll()[0];
}
return res;
}
}
对于比较器的使用:
如果自定义优先级队列比较器:
- PriorityQueue默认是升序
- 自定义类比较器的用法:
public class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } } //自定义比较类,升序排列 static Comparator<ListNode> cLNode = new Comparator<ListNode>() { public int compare(ListNode o1, ListNode o2) { return o1.val-o2.val; } }; public static void main(String[] args) { //自定义类的优先队列需要重写比较类作为传入参数 //Queue<ListNode> que = new PriorityQueue<>(cLNode); //简单写法 ,这里题中的解法就是用的简单的写法; Queue<ListNode> que = new PriorityQueue<>((v1, v2) -> v1.val - v2.val); }