347. 前 K 个高频元素
题目要求解题思路代码
题目要求
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
解题思路
这题首先有一个坑:题目给你的方法是List< Integer>但是题目要求的返回类型是int[] 所以第一步,就是要把方法的类型换成int[]。 然后这个问题是个TopK问题,所以可以考虑用堆来解决。 定义一个最大堆(用小顶堆实现)。当堆中元素达到K个后,再放入的元素与堆顶元素进行比较,如果小于堆顶元素,那么就将它丢弃。如果大于堆顶元素,就将它插入堆,并且丢弃掉之前的堆顶元素
TopK Elements 问题,简单来说就是在一堆数据里面找到前 K 小(当然也可以是前 K 大)的数。可以维护一个大小为 K 的最小堆(这里的堆和JVM中的堆是两个概念),最小堆中的元素就是最小元素。最小堆需要使用大顶堆来实现,大顶堆表示堆顶元素是堆中最大元素。这是因为我们要得到 k 个最小的元素,因此当遍历到一个新的元素时,需要知道这个新元素是否比堆中最大的元素更小,更小的话就把堆中最大元素去除,并将新元素添加到堆中,再重新排序。
堆也可以用于求解 Kth Element 问题,也就是第 K 个元素的问题,得到了大小为 k 的最小堆之后,因为使用了大顶堆来实现,因此堆顶元素就是第 k 大的元素。
代码
class Solution {
public int[] topKFrequent(int[] nums
, int k
) {
if (nums
== null
) {
return null
;
}
Map
<Integer,Integer> map
=new HashMap<>();
for(int num
:nums
){
if (map
.containsKey(num
)){
map
.put(num
,map
.get(num
)+1);
}else {
map
.put(num
,1);
}
}
PriorityQueue
<Integer> pq
=new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1
, Integer o2
) {
return map
.get(o1
)-map
.get(o2
);
}
});
for (Integer key
:map
.keySet()){
if (pq
.size()<k
){
pq
.add(key
);
}
else if(map
.get(key
)>map
.get(pq
.peek())){
pq
.remove();
pq
.add(key
);
}
}
List
<Integer> res
= new ArrayList<>();
while (!pq
.isEmpty()) {
res
.add(pq
.remove());
}
int[] arr
= res
.stream().mapToInt(Integer
::valueOf
).toArray();
return arr
;
}
}