给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements
/**
* 前 K 个高频元素
* 最笨的写法,先hashmap去重,再list降序排序,去前k个元素
* @param nums
* @param k
* @return
*/
public List<Integer> topKFrequent(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return new ArrayList<>();
}
List<Integer> list = new ArrayList<>();
//去重
Map<Integer,Integer> map = new HashMap<>();
for (int n :nums){
if (map.containsKey(n)) {
map.put(n,map.get(n)+1);
}else {
map.put(n,1);
}
}
//排序
List<Map.Entry<Integer,Integer>> sortList = new ArrayList<>(map.entrySet());
Collections.sort(sortList, new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue() - o1.getValue();
}
});
//过滤
int count = 0;
for (Map.Entry<Integer,Integer> entry : sortList){
list.add(entry.getKey());
count++;
if (count >= k) {
break;
}
}
return list;
}
/**
* 最小堆的实现方式(堆采用PriorityQueue,堆大小为k)
* 思路:将上面笨方法中全排序的方法换成最小堆的方式排序,堆的大小为k
* @param nums
* @param k
* @return
*/
public List<Integer> topKFrequent1(int[] nums, int k) {
if (nums == null || nums.length == 0){
return new ArrayList<>();
}
final Map<Integer,Integer> map = new HashMap<>();
for (int m : nums){
if (map.containsKey(m)) {
map.put(m,map.get(m)+1);
}else {
map.put(m,1);
}
}
//升序的队列
//remove()方法也是调用pop(),只是去除null值
PriorityQueue<Integer> priorityQueue = new PriorityQueue(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return map.get(o1) - map.get(o2);
}
});
for (Integer n : map.keySet()){
if (priorityQueue.size() < k) {
priorityQueue.offer(n);
} else if (map.get(n) > map.get(priorityQueue.peek())) {
priorityQueue.remove();
priorityQueue.offer(n);
}
}
List<Integer> list = new ArrayList<>();
while (!priorityQueue.isEmpty()) {
list.add(priorityQueue.remove());
}
return list;
}
/**
* 桶排序(bucket sort)
* 使用List数组存储,
* 考虑到统计的元素个数可用有重复的,存储在同一个数组下标中的list中
* @param nums
* @param k
* @return
*/
public List<Integer> topKFrequent2(int[] nums, int k) {
if (nums == null || nums.length == 0){
return new ArrayList<>();
}
//去重,统计次数
Map<Integer,Integer> map = new HashMap<>();
for (int n : nums){
if (map.containsKey(n)) {
map.put(n,map.get(n)+1);
}else {
map.put(n,0);
}
}
List<Integer> list = new ArrayList<>();
//桶排序
List<Integer>[] bucket = new List[nums.length];
for (Integer key: map.keySet()){
if (bucket[map.get(key)] == null) {
bucket[map.get(key)] = new ArrayList<>();
}
bucket[map.get(key)].add(key);
}
//倒序输出有效元素
for (int i = nums.length; i >= 0 && list.size() < k; i--) {
if (bucket[i] != null) {
list.addAll(bucket[i]);
}
}
return list;
}