Question
Given a non-empty array of integers, return the k most frequent elements.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Example 2:
Input: nums = [1], k = 1
Output: [1]
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.
\(O(nlogn)\) Solution
Use a heap to find the k most frequent elements.
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> frequency = new HashMap<>();
for(int n: nums) {
frequency.put(n, frequency.getOrDefault(n, 0) + 1);
}
PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>(Map.Entry.comparingByValue(Comparator.reverseOrder()));
for(Map.Entry<Integer, Integer> entry: frequency.entrySet()) {
pq.offer(entry);
}
List<Integer> res = new ArrayList<>(k);
for(int i = 0; i < k; i++) {
res.add(pq.poll().getKey());
}
return res;
}
}
\(O(n)\) Solution
Use bucket sort to find frequencies in descending order.
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> frequency = new HashMap<>();
for(int n: nums) {
frequency.put(n, frequency.getOrDefault(n, 0) + 1);
}
Map<Integer, List<Integer>> buckets = new TreeMap<>();
for(Map.Entry<Integer, Integer> entry: frequency.entrySet()) {
buckets.computeIfAbsent(entry.getValue(), kk -> new LinkedList<>()).add(entry.getKey());
}
List<Integer> res = new ArrayList<>(k);
for(int i = 0, j = nums.length; j > 0 && i < k; j--) {
if(buckets.containsKey(j)) {
res.addAll(buckets.get(j));
i += buckets.get(j).size();
}
}
return res;
}
}