import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
// 最小堆
/**
* 具体操作为:
* 借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
* 维护一个元素数目为 k 的最小堆
* 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
* 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
* 最终,堆中的 k 个元素即为前 k 个高频元素
*/
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
// 元素进map
for (int num : nums) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 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[] result = new int[k];
int index = 0;
while (!pq.isEmpty()) {
result[index] = pq.remove();
index++;
}
return result;
}
}
// 桶排序法
// 没有解决输入元素为负的情况
/**
* 首先依旧使用哈希表统计频率,统计完成后,创建一个数组,将频率作为数组下标,
* 对于出现频率不同的数字集合,存入对应的数组下标即可。
*/
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
// 元素进map
for (int num : nums) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//桶排序
//将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
int[] list = new int[nums.length + 1];
for (int key : map.keySet()) {
// 获取出现的次数作为下标
int i = map.get(key);
list[key] = i;
}
// 倒序遍历数组获取出现顺序从大到小的排列
int[] result = new int[k];
int index = 0;
for (int i = list.length - 1; i >= 0 && index < result.length; i--) {
// 跳过值为零的也就是没存元素的数组
if (list[i] == 0) continue;
result[index] = list[i];
index++;
}
return result;
}
}
leetcode347. 前 K 个高频元素
最新推荐文章于 2023-06-08 13:56:47 发布