Description
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
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 <= 105-104 <= nums[i] <= 104kis in the range[1, the number of unique elements in the array].- It is guaranteed that the answer is unique.
Approach 0
- So first create a frequency map with input integer as key and their frequency as value
- Now we will create an array whose elements are
List<Integer>the purpose being frequency as key and the elements with that frequency stored as a List - The size would be input array length as the most frequency someone can have is that
- So now we just iterate through this array in reverse and return k elements
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> freq = new HashMap<>();
List<Integer>[] bucket = new ArrayList[nums.length + 1];
for (int num: nums) {
freq.put(num, freq.getOrDefault(num,0) + 1);
}
for (int key: freq.keySet()) {
int count = freq.get(key);
if(bucket[count] == null) {
bucket[count] = new ArrayList<>();
}
bucket[count].add(key);
}
int index = 0;
int[] res = new int[k];
for(int i = nums.length; i >= 0; i--) {
if(bucket[i] != null) {
for(int val: bucket[i]) {
res[index++] = val;
if(index == k) {
return res;
}
}
}
}
return res;
}
}Approach 1: Max-Heap / Sorting
Intuition
Count the frequency of each element using a hash map. Push all unique numbers into a Max-Heap sorted by their frequency, then pop the top k elements.
import java.util.*;
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> countMap = new HashMap<>();
for (int num : nums) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> countMap.get(b) - countMap.get(a));
for (int num : countMap.keySet()) {
maxHeap.add(num);
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = maxHeap.poll();
}
return result;
}
}
Complexity
- Time Complexity: — Where is the number of unique elements in
nums. In the worst case . - Space Complexity: — Map and heap store up to unique elements.
Approach 2: Min-Heap of Size
Intuition
Build a frequency map. Instead of storing all unique elements in a Max-Heap, maintain a Min-Heap of size at most k. If the heap grows past size k, pop the least frequent element. When done, the heap holds the top k most frequent elements.
import java.util.*;
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> countMap = new HashMap<>();
for (int num : nums) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
// Min-Heap ordered by frequency
PriorityQueue<Integer> minHeap = new PriorityQueue<>((a, b) -> countMap.get(a) - countMap.get(b));
for (int num : countMap.keySet()) {
minHeap.add(num);
if (minHeap.size() > k) {
minHeap.poll(); // Evict the element with the lowest frequency
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = minHeap.poll();
}
return result;
}
}
Complexity
- Time Complexity: — to build frequency map, to maintain Min-Heap of size .
- Space Complexity: — Map stores elements and heap stores up to elements.
Most Optimized Solution: Bucket Sort ( Time)
Intuition
Since an element can appear at most times, create an array of lists bucket of size , where index i holds elements that appear exactly i times. Iterate backwards from frequency down to to collect the top k frequent numbers.
import java.util.*;
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> countMap = new HashMap<>();
for (int num : nums) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
// Index = frequency, Value = list of numbers with that frequency
List<Integer>[] bucket = new List[nums.length + 1];
for (int key : countMap.keySet()) {
int freq = countMap.get(key);
if (bucket[freq] == null) {
bucket[freq] = new ArrayList<>();
}
bucket[freq].add(key);
}
int[] result = new int[k];
int index = 0;
// Traverse backwards from highest possible frequency
for (int i = bucket.length - 1; i >= 0 && index < k; i--) {
if (bucket[i] != null) {
for (int num : bucket[i]) {
result[index++] = num;
if (index == k) {
return result;
}
}
}
}
return result;
}
}
Complexity
- Time Complexity: — Linear scan to count frequencies and populate buckets.
- Space Complexity: — Buckets and frequency map store at most elements.
Easy Memory Rule
“Frequency map Array of Buckets where index = frequency Traverse from back to front until items collected.”