题目
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1. 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
2. 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
3. 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
4. 你可以按任意顺序返回答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements
解题
哈希排序
自己首先的思路就是用一个哈希表存储每个元素以及它们在数组中出现的次数,然后将该哈希依照次数进行排序,然后再依次输出。(重点:哈希表中比较器排序的写法)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int[] res = new int[k];
//建立一个按value排序的HashMap
Map<Integer, Integer> map = new HashMap<Integer, Integer>();//key保存 数组元素值,value保存该值出现次数
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
//比较器 list将map中的每个<key,value>即为一个entry保存为一个list
List<Map.Entry<Integer,Integer>> list = new ArrayList<Map.Entry<Integer,Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>(){
//降序排序
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2){
return o2.getValue().compareTo(o1.getValue());
}
});
//输出map中前k个
//写法1
//int i = 0;
//for(Map.Entry<Integer, Integer> mapping:list){
// if(i == k){
// break;
// }else{
// res[i] = mapping.getKey();
// }
// i++;
//}
//写法2
for(int i = 0 ; i < k; i++){
res[i] = list.get(i).getKey();
}
return res;
}
}
TopK问题解法
参考以及代码来源: 4 种方法秒杀 TopK(计数排序/快排变形/堆/二叉搜索树)
其实是几种比较优秀的排序算法的应用,对排序算法不了解可以先看这篇:十种排序算法详解&Java实现
TopK问题,不管是求前K大/前K小/第K大/第K小,都有以下四种不错的方法:
- O(N):用快排变形最最高效解决TopK问题
- O(NlogK):大根堆(前K小)/小根堆(前K大)
- O(NlogK):二叉搜索树
- O(N):对于数据范围有限的情况下,可以用计数排序O(N)高效解决。
其中的很多方法其实在求TopK问题时,是不需要对整个序列进行排序的,应用一些较快的排序思想,在排序过程中就可得到结果,而不需全部排序完毕。
快排变形
因为每次快排是选出一个数(一般从第一个数开始)经过一系列交换找到该数在整个序列中所在的位置,对整个序列进行一次切分,结果为该数左边为比该数小的元素,右边为比该数大的元素。所以在解决TopK问题时,如果这次快排选出的数正好是第K个元素,结果已经出来了;如果不是根据两者的大小关系,看下次切分从哪个范围内选择数值即下次切分右段还是左段。
class Solution {
class</