题目描述
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
解题思路
- 借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
- 维护一个元素数目为 k 的最小堆
- 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
- 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
- 最终,堆中的 k 个元素即为前 k 个高频元素
最小堆:
import java.util.*;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution_347 {
/**
* 堆排序
* @param nums
* @param k
* @return
*/
public int[] topKFrequent(int[] nums, int k) {
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i],map.getOrDefault(nums[i],0) + 1);
}
// 遍历map,用最小堆保存频率最大的k个元素
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
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);
}
}
//取出最小堆中的元素
int[] res = new int[k];
for (int i = 0; i < k; i++) {
res[i] = pq.remove();
}
return res;
}
}
感觉这个代码是堆排序中的灵魂:
// 遍历map,用最小堆保存频率最大的k个元素
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
桶排序法
首先依旧使用哈希表统计频率,统计完成后,创建一个数组,将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标即可。
//基于桶排序求解「前 K 个高频元素」
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> res = new ArrayList();
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i],map.getOrDefault(nums[i],0) + 1);
}
//桶排序
//将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
List<Integer>[] list = new List[nums.length+1];
for(int key : map.keySet()){
// 获取出现的次数作为下标
int i = map.get(key);
if(list[i] == null){
list[i] = new ArrayList();
}
list[i].add(key);
}
// 倒序遍历数组获取出现顺序从大到小的排列
for(int i = list.length - 1;i >= 0 && res.size() < k;i--){
if(list[i] == null) continue;
res.addAll(list[i]);
}
return res;
}
}