题目
思路
1.统计每个数出现的次数:可以用HashMap。key为num,value为这个数出现的次数。
2.怎样返回HashMap中value最大的前k个key呢?
这里用优先队列的方法(本质是堆)
我们要维护一个小根堆。我们在堆中存储(key,value)这个节点,并按value进行堆的搭建。根据小根堆的定义,根节点值是最小的。也就是根节点对应的频次最少。
当有新的节点进来时,我们和根节点进行比较,如果频次大于根节点,根节点出去,新节点进来。用堆的话,还有一个好处就是我们只需要维护一个有k个节点的堆就行了。随着我们遍历一个个hashmap的<key,value>,我们始终让堆中节点为k,最后遍历完hashmap了,我们把堆中元素输出即可。
基础知识
优先队列:java提供了它的类。本质是堆。
pq=new PriorityQueue<>()。但是里面要传入一个重写compare方法的对象,指定它是从小到大,还是从大到小排序。
java compare方法排序理解-CSDN博客 我的前一篇讲了compare方法的理解。
pq.poll()弹出队头元素,也就是根节点元素。
pq.add()加入一个新元素,会自动调整位置,以符合(大根/小根)堆的性质
代码
class Solution {public int[] topKFrequent2(int[] nums, int k) {Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数for(int num:nums){map.put(num,map.getOrDefault(num,0)+1);}//在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数//出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(相当于小顶堆)PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序if(pq.size()<k){//小顶堆元素个数小于k个时直接加pq.add(new int[]{entry.getKey(),entry.getValue()});}else{if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)pq.poll();//弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了pq.add(new int[]{entry.getKey(),entry.getValue()});}}}int[] ans = new int[k];for(int i=k-1;i>=0;i--){//依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多ans[i] = pq.poll()[0];}return ans;}
}