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] <= 104
  • k is 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.”