问题描述
Given a non-empty array of integers, return the k most frequent elements.
For example,
Given[1,1,1,2,2,3]
andk = 2
, return[1,2]
.Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
- 地址
问题分析
- 属于 Top K 问题范畴,类似于 LeetCode 215. Kth Largest Element in an Array ,只不过该题是求为出现次数的 Top K 所对应的元素。所以首先需要用 map 来统计次数。然后分为两种做法:
- 用堆。用一个大小为 K 的最小堆,来始终维护出现次数 Top K 的元素。堆里存的是一个对象。时间复杂度: O(NlogK)
也有人用一个最大堆来维护出现次数 为 map.size() - k 小的元素,剩下的便是出现次数 Top K 的元素。 - 用桶排序,创建一个
list
数组 bucket, bucket[i] 用来存储所有出现次数为i
的元素。然后再从后向前遍历 bucket数组,找到k个元素为止。
- 用堆。用一个大小为 K 的最小堆,来始终维护出现次数 Top K 的元素。堆里存的是一个对象。时间复杂度: O(NlogK)
代码实现
- 堆
public List<Integer> topKFrequent(int[] nums, int k) {
if(nums == null || k <= 0 || k > nums.length) {
return 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);
}
PriorityQueue<Node> minHeap = new PriorityQueue<>(new Comparator<Node>() {
public int compare(Node o1, Node o2) {
return o1.freq - o2.freq;
}
});
for (Integer key : map.keySet()) {
int freq = map.get(key);
if (minHeap.size() == k && freq > minHeap.peek().freq) {
minHeap.poll();
minHeap.add(new Node(key, freq));
}
if (minHeap.size() < k) {
minHeap.add(new Node(key, freq));
}
}
ArrayList<Integer> res = new ArrayList<>();
//将堆中元素加入res
for (Node curNode : minHeap) {
res.add(curNode.val);
}
Collections.reverse(res);
return res;
}
- 桶排序
public List<Integer> topKFrequent(int[] nums, int k) {
if(nums == null || k <= 0 || k > nums.length) {
return 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>[] bucket = new List[nums.length + 1];
for (int key : map.keySet()) {
int val = map.get(key);
if (bucket[val] == null) {
bucket[val] = new ArrayList<Integer>();
}
bucket[val].add(key);
}
List<Integer> res = new ArrayList<>();
int count = 0;
for (int i = bucket.length - 1; i >=0; i--) {
if (bucket[i] == null) {
continue;
}
for (int j = 0; j < bucket[i].size() && count < k; j++) {
res.add(bucket[i].get(j));
++count;
}
}
return res;
}