Problem
Given an integer array nums
and an integer k
, return the k
most frequent elements. You may return the answer in any order.
Examples
Example 1:
Input nums = [1,1,1,2,2,3], k = 2
Output [1,2]
Example 2:
Input nums = [1], k = 1
Output [1]
Constraints
1 <= nums.length <= 10^5
k
is in the range[1, the number of unique elements in the array]
.- It is guaranteed that the answer is unique.
Solution
Method 1 - Sorting
We can create a map of number and frequency. Sort the map based on frequency and return first k elements. But the time complexity will be O(n log n). But of course we can do better.
Method 2 - Using HashMap and Min Heap 🥈
We can
- Create frequency map - Use a hashmap or dictionary to count the frequency of each unique element in
nums
. - Create min heap of size k based on frequency and run the map through it.
Code
Java
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> freq = new HashMap<>(); // Frequency count
for (int num : nums) {
freq.put(num, freq.getOrDefault(num, 0) + 1);
}
// Using a priority queue (min-heap)
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[0] - b[0]);
for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
heap.add(new int[]{entry.getValue(), entry.getKey()});
if (heap.size() > k) heap.poll();
}
List<Integer> ans = new ArrayList<>();
for (int[] pair : heap) ans.add(pair[1]);
return ans;
}
}
Python
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freq = Counter(nums) # Frequency count
# Using a min-heap to keep the k most frequent elements
heap = [(count, num) for num, count in freq.items()]
heapq.heapify(heap)
ans = heapq.nlargest(k, heap)
return [num for _, num in ans]
Complexity
- ⏰ Time complexity:
O(n log k)
, wheren
is the size ofnums
andk
is size of min heap.- Count the frequency of elements in
O(n)
using a hashmap. - O(
n log k
) for using min heap O(n + k)
using bucket sort.
- Count the frequency of elements in
- 🧺 Space complexity:
O(n)
, for the hashmap and additional data structures.
Method 3 - Bucket Sort 🏆
We can use array of linked list, where we can bucketize the numbers based on there frequency. The bucket index will be frequency, values will be number added to that bucket.
Number of buckets will be = nums.length+1. Why? Because what if all the element occur once, then it is nums.length; Also, 0 for 0 frequency case. This helps in avoiding edge cases, where we need to sometimes do index-1
etc.
Code
Java
public int[] topKFrequent(int[] nums, int k) {
List<Integer>[] bucket = new List[nums.length + 1];
Map<Integer, Integer> frequencyMap = new HashMap<>();
for (int num : nums) {
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
}
for (int key : frequencyMap.keySet()) {
int frequency = frequencyMap.get(key);
if (bucket[frequency] == null) {
bucket[frequency] = new ArrayList<>();
}
bucket[frequency].add(key);
}
int[] ans = new int[k];
int j = 0;
for (int pos = bucket.length - 1; pos >= 0; pos--) {
if(bucket[pos] == null) {
continue;
}
List<Integer> currBucket = bucket[pos];
for(int i =0; i< currBucket.size() && j < k; i++){
ans[j++] = currBucket.get(i);
}
}
return ans;
}
Python
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# Frequency count using Counter
freq = Counter(nums)
# Bucket where index represents frequency
bucket: List[List[int]] = [[] for _ in range(len(nums) + 1)]
# Fill the bucket
for num, count in freq.items():
bucket[count].append(num)
# Extract the top k frequent elements
ans = []
for i in range(len(bucket) - 1, 0, -1): # Traverse bucket from high to low frequency
if bucket[i]:
ans.extend(bucket[i]) # Add all elements in the current bucket
if len(ans) >= k: # Stop when we have enough elements
return ans[:k]
return ans
Complexity
- ⏰ Time complexity:
O(n)
each to count frequencies, populate the bucket and collect the topk
frequent elements. - 🧺 Space complexity:
O(n)
for the frequency map and bucket.