给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
- 示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2] - 示例 2:
输入: nums = [1], k = 1
输出: [1]
思路
- 要统计元素出现频率
- 对频率排序
- 找出前K个高频元素
首先统计元素出现的频率,这一类的问题可以使用map来进行统计,根据map的value排序。
然后是对频率进行排序,这里我们可以使用一种 容器适配器就是==优先级队列==。
方法一: 根据map的value排序
1.将 nums
的数字和频次放入map中
我们将 key
设置为 num 中出现的数字
, value
设置为出现的频次
.
map.getOrDefault(num, 0)
是一个Map
接口的方法调用,用于获取给定键 num
对应的值,如果键不存在,则返回默认值 0
。
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
2.将Map的键值
对转换为List
map.entrySet()
是 Map
接口中的一个方法,它返回一个包含 Map
中所有键值对(Entry)的集合。具体来说,它返回一个 Set
集合,该集合中的每个元素都是一个 Map.Entry
对象,表示 Map
中的一个键值对。
每个 Map.Entry
对象都包含两个方法:getKey()
和 getValue()
,用于获取键和对应的值。
List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(map.entrySet());
3.使用Comparator
对List
进行排序
Comparator.reverseOrder()
按值从大到小排序
entryList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));
4.遍历排序后的List
, 根据value
排序
int cnt = 0;
for(Map.Entry<Integer, Integer> entry : entryList){
res[cnt++] = entry.getKey();
System.out.println(entry.getKey() + " -> " + entry.getValue());
if (cnt == k ) break;
}
5.最终代码
/**
* 方法一: 根据 Map 的 value 进行排序
* @param nums
* @param k
* @return
*/
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[k];
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
// 1.将Map的键值对转换为List
List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(map.entrySet());
// 2.使用Comparator对List进行排序
// Comparator.reverseOrder()按值从大到小排序
entryList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));
// 3.遍历排序后的List
int cnt = 0;
for(Map.Entry<Integer, Integer> entry : entryList){
res[cnt++] = entry.getKey();
System.out.println(entry.getKey() + " -> " + entry.getValue());
if (cnt == k ) break;
}
return res;
}
方法二: 基于小顶堆
1.将 nums
的数字和频次放入map中
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
2.设置优先级队列
优先级队列(Priority Queue)是一种特殊的队列数据结构,它可以根据元素的优先级进行排序和访问。具体可见
// (Comparator.comparingInt(o -> o[1]) 将按照数组中索引为1的元素的大小对二维数组进行排序
PriorityQueue<int[]> pq = new PriorityQueue<>((Comparator.comparingInt(o -> o[1])));
3.获取键值对, 插入优先级队列
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
// 获取 k-v int[] tmp = new int[2];
tmp[0] = entry.getKey();
tmp[1] = entry.getValue();
// 进入优先队列
pq.offer(tmp);
// 根据小顶堆进行排序, 仅有 k 个元素在堆里面, 多到的需要出队
if (pq.size() > k){
pq.poll();
}
}
4.通过优先级队列构造k个节点的小顶堆完成, 取出元素即可
for (int i = 0; i < k; i++) {
int[] tmp = pq.poll();
res[i] = tmp[0];
System.out.println("[" + tmp[0] + tmp[1] + "]");
}