# Question

Formatted question description: https://leetcode.ca/all/347.html

# 347. Top K Frequent Elements

Medium

## Description

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.

## Solution

Similar to 692-Top-K-Frequent-Words

To achieve an algorithm with a time complexity better than O(n log n), we can leverage mappings. This approach yields a time complexity of O(n log k).

The strategy involves the use of two maps:

• The first map is a hash map that keeps track of each number and its corresponding count.
• The second map is a tree map, which organizes each count and the numbers associated with that count. The key distinction here is that the tree map sorts its keys.

### Implementation Steps

1. Counting Occurrences: Iterate over the nums array to tally the occurrence of each number. Store this information in the first map, with the numbers as keys and their counts as values.

2. Organizing Counts: Process the entries of the first map to compile each count and the associated numbers. Insert these into the second map, ensuring that the counts (keys) are in descending order. This setup enables us to efficiently access numbers based on their frequency.

3. Selecting Top Frequencies: Traverse the second map to extract the k most frequent elements. This step is streamlined by the descending order of counts in the map.

### Consideration

A potential complication arises in situations of frequency ties. The solution must account for how to prioritize numbers when multiple values share the same count. This clarification impacts the selection of the k most frequent elements, especially when the exact ordering or choice of elements within tied groups influences the outcome.

# Code

• import java.util.*;

public class Top_K_Frequent_Elements {

// ref: https://leetcode.com/problems/top-k-frequent-elements/solution/

class Solution_official_oN {
int[] unique;
Map<Integer, Integer> count;

public void swap(int a, int b) {
int tmp = unique[a];
unique[a] = unique[b];
unique[b] = tmp;
}

public int partition(int left, int right, int pivot_index) {
int pivot_frequency = count.get(unique[pivot_index]);
// 1. move pivot to end
swap(pivot_index, right);
int store_index = left;

// 2. move all less frequent elements to the left
for (int i = left; i <= right; i++) {
if (count.get(unique[i]) < pivot_frequency) {
swap(store_index, i);
store_index++;
}
}

// 3. move pivot to its final place
swap(store_index, right);

return store_index;
}

public void quickselect(int left, int right, int k_smallest) {
/*
Sort a list within left..right till kth less frequent element
takes its place.
*/

// base case: the list contains only one element
if (left == right) return;

// select a random pivot_index
Random random_num = new Random();
int pivot_index = left + random_num.nextInt(right - left);

// find the pivot position in a sorted list
pivot_index = partition(left, right, pivot_index);

// if the pivot is in its final sorted position
if (k_smallest == pivot_index) {
return;
} else if (k_smallest < pivot_index) {
// go left
quickselect(left, pivot_index - 1, k_smallest);
} else {
// go right
quickselect(pivot_index + 1, right, k_smallest);
}
}

public int[] topKFrequent(int[] nums, int k) {
// build hash map : character and how often it appears
count = new HashMap<>();
for (int num: nums) {
count.put(num, count.getOrDefault(num, 0) + 1);
}

// array of unique elements
int n = count.size();
unique = new int[n];
int i = 0;
for (int num: count.keySet()) {
unique[i] = num;
i++;
}

// kth top frequent element is (n - k)th less frequent.
// Do a partial sort: from less frequent to the most frequent, till
// (n - k)th less frequent element takes its place (n - k) in a sorted array.
// All element on the left are less frequent.
// All the elements on the right are more frequent.
quickselect(0, n - 1, n - k);
return Arrays.copyOfRange(unique, n - k, n);
}
}

class Solution_optimize {
public int[] topKFrequent(int[] nums, int k) {
// O(1) time
if (k == nums.length) {
return nums;
}

// 1. build hash map : character and how often it appears
// O(N) time
Map<Integer, Integer> countMap = new HashMap();
for (int n: nums) {
countMap.put(n, countMap.getOrDefault(n, 0) + 1);
}

// init heap 'the less frequent element first', poll到最后剩下K个最大的
Queue<Integer> heap = new PriorityQueue<>(
(n1, n2) -> countMap.get(n1) - countMap.get(n2));

// 2. keep k top frequent elements in the heap
// O(N log k) < O(N log N) time
for (int n: countMap.keySet()) {
if (heap.size() > k) heap.poll();
}

// 3. build an output array
// O(k log k) time
int[] top = new int[k];
for(int i = k - 1; i >= 0; --i) {
top[i] = heap.poll();
}
}
}

// use an array to save numbers into different bucket whose index is the frequency
public class Solution_bucketCount {
public List<Integer> topKFrequent(int[] nums, int k) {

if (nums == null || nums.length == 0) {
return result;
}

Map<Integer, Integer> hm = new HashMap<>();
for(int n: nums){
hm.put(n, hm.getOrDefault(n, 0) + 1);
}

// @note: corner case: if there is only one number in nums, we need the bucket has index 1.

for(int n: hm.keySet()){
int freq = hm.get(n);
if(bucket[freq] == null) {
}
}

for(int i = bucket.length - 1; i > 0 && k > 0; i--){

// @note: possible tie happening
if(bucket[i] != null){
List<Integer> list = bucket[i];
k-= list.size();
}
}

return result;
}
}

class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {

List<Integer> result = new ArrayList<>();

if (nums == null || nums.length == 0) {
return result;
}

// from num, to its count
HashMap<Integer, Integer> hm = new HashMap<>();

// to store top k
PriorityQueue<Pair> heap = new PriorityQueue<>(
(o1, o2) -> (o1.count - o2.count)
);

for (int each: nums) {
hm.put(each, 1 + hm.getOrDefault(each, 0));
}

for (Map.Entry<Integer, Integer> entry: hm.entrySet()) {
heap.offer(new Pair(entry.getKey(), entry.getValue()));

// @note: i missed it
if (heap.size() > k) {
heap.poll();
}
}

while (!heap.isEmpty()) {
}

Collections.reverse(result);

return result;
}
}

class Pair{
int num;
int count;
public Pair(int num, int count){
this.num=num;
this.count=count;
}
}
}

//////

class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Long> frequency = Arrays.stream(nums).boxed().collect(
Collectors.groupingBy(Function.identity(), Collectors.counting()));
Queue<Map.Entry<Integer, Long>> queue = new PriorityQueue<>(Map.Entry.comparingByValue());
for (var entry : frequency.entrySet()) {
queue.offer(entry);
if (queue.size() > k) {
queue.poll();
}
}
return queue.stream().mapToInt(Map.Entry::getKey).toArray();
}
}


• // OJ: https://leetcode.com/problems/top-k-frequent-elements/
// Time: O(N + U) on average, O(N + U^2) in the worst case
// Space: O(U)
class Solution {
public:
vector<int> topKFrequent(vector<int>& A, int k) {
if (A.size() == k) return A;
unordered_map<int, int> cnt;
for (int n : A) cnt[n]++;
vector<int> ans;
for (auto &[n, c] : cnt) ans.push_back(n);
if (ans.size() == k) return ans;
auto partition = [&](int L, int R) {
int i = L, j = L, pivotIndex = L + rand() % (R - L + 1), pivot = cnt[ans[pivotIndex]];
swap(ans[pivotIndex], ans[R]);
for (; i < R; ++i) {
if (cnt[ans[i]] > pivot) swap(ans[i], ans[j++]);
}
swap(ans[j], ans[R]);
return j;
};
auto quickSelect = [&](int k) {
int L = 0, R = ans.size() - 1;
while (L < R) {
int M = partition(L, R);
if (M + 1 == k) break;
if (M + 1 > k) R = M - 1;
else L = M + 1;
}
};
quickSelect(k);
ans.resize(k);
return ans;
}
};

• '''
>>> nums = ["a", "a", "b", "c", "c"]

>>> cnt = Counter(nums)
>>> cnt
Counter({'a': 2, 'c': 2, 'b': 1})

# default to keys
>>> sorted_freqs = sorted(cnt, key=lambda x: (-cnt[x], x))
>>> sorted_freqs
['a', 'c', 'b']
'''
from collections import Counter

class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# Count the frequency of each element in the list
cnt = Counter(nums)

# Sort the elements by frequency in decreasing order
# diff from below solution: sorted(cnt), not sorted(cnt.items())
#   more in https://leetcode.ca/2017-10-22-692-Top-K-Frequent-Words/
sorted_freqs = sorted(cnt, key=lambda x: (-cnt[x], x))

return sorted_freqs[:k]

##############

class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# Count the frequency of each element in the list
freqs = Counter(nums)

# Sort the elements by frequency in decreasing order
sorted_freqs = sorted(freqs.items(), key=lambda x: x[1], reverse=True)
# also passing OJ: sorted_freqs = sorted(freqs.items(), key=lambda x: -x[1])

# Take the top k elements
top_k = [num for num, freq in sorted_freqs[:k]]

##############

'''
>>> from heapq import heappush
>>> h = []
>>> heappush(h, (3,1))
>>> heappush(h, (1,1))
>>> heappush(h, (2,1))
>>> h
[(1, 1), (3, 1), (2, 1)]

>>> from heapq import heappop
>>> heappop(h)
(1, 1)
>>> heappop(h)
(2, 1)
>>> heappop(h)
(3, 1)
'''

from collections import Counter

class Solution: # heap
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
cnt = Counter(nums)
hp = []
for num, freq in cnt.items():
heappush(hp, (freq, num)) # freq first, default sort by 1st element
if len(hp) > k:
heappop(hp)
return [v[1] for v in hp]

##############

from typing import List
import random
# O(n log(n)) in the average case
# O(n^2) worst case
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freq_map = {}
for num in nums:
freq_map[num] = freq_map.get(num, 0) + 1

freq_list = list(freq_map.items())
self.quick_select(freq_list, 0, len(freq_list) - 1, k)

return [num for num, freq in freq_list[:k]]

def quick_select(self, freq_list, start, end, k):
if start == end:
return

pivot_idx = random.randint(start, end)
pivot_freq = freq_list[pivot_idx][1]

left = start
right = end

while left <= right:
while freq_list[left][1] > pivot_freq:
left += 1
while freq_list[right][1] < pivot_freq:
right -= 1

if left <= right:
freq_list[left], freq_list[right] = freq_list[right], freq_list[left]
left += 1
right -= 1

if k <= right:
self.quick_select(freq_list, start, right, k)
elif k >= left:
self.quick_select(freq_list, left, end, k)

###########

'''
>>> x = [1, 2, 3]
>>> x.append([4, 5])
>>> print(x)
[1, 2, 3, [4, 5]]

>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> print(x)
[1, 2, 3, 4, 5]
'''
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freq = Counter(nums)

# not always filled, max possible frequency is len(nums) [1,1,1,1,...]
buckets = [[] for _ in range(len(nums) + 1)]
for num, freq in freq.items():
buckets[freq].append(num)

res = []
for bucket in reversed(buckets):
if bucket:
res.extend(bucket)
if len(res) >= k:
break

return res[:k]

############

class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
d = {}
res = []
ans = []
buckets = [[] for _ in range(len(nums) + 1)]

for num in nums:
d[num] = d.get(num, 0) + 1

for key in d:
res.append((d[key], key))

for t in res:
freq, key = t
buckets[freq].append(key)

buckets.reverse()

for item in buckets:
if item and k > 0:
while item and k > 0:
ans.append(item.pop())
k -= 1
if k == 0:
return ans

return ans


• func topKFrequent(nums []int, k int) []int {
cnt := map[int]int{}
for _, v := range nums {
cnt[v]++
}
h := hp{}
for v, freq := range cnt {
heap.Push(&h, pair{v, freq})
if len(h) > k {
heap.Pop(&h)
}
}
ans := make([]int, k)
for i := range ans {
ans[i] = heap.Pop(&h).(pair).v
}
return ans
}

type pair struct{ v, cnt int }
type hp []pair

func (h hp) Len() int            { return len(h) }
func (h hp) Less(i, j int) bool  { return h[i].cnt < h[j].cnt }
func (h hp) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{}) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() interface{}   { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }

• function topKFrequent(nums: number[], k: number): number[] {
let hashMap = new Map();
for (let num of nums) {
hashMap.set(num, (hashMap.get(num) || 0) + 1);
}
let list = [...hashMap];
list.sort((a, b) => b[1] - a[1]);
let ans = [];
for (let i = 0; i < k; i++) {
ans.push(list[i][0]);
}
return ans;
}


• use std::collections::HashMap;
impl Solution {
pub fn top_k_frequent(nums: Vec<i32>, k: i32) -> Vec<i32> {
let mut map = HashMap::new();
let mut max_count = 0;
for &num in nums.iter() {
let val = map.get(&num).unwrap_or(&0) + 1;
map.insert(num, val);
max_count = max_count.max(val);
}
let mut k = k as usize;
let mut res = vec![0; k];
while k > 0 {
let mut next = 0;
for key in map.keys() {
let val = map[key];
if val == max_count {
res[k - 1] = *key;
k -= 1;
} else if val < max_count {
next = next.max(val);
}
}
max_count = next;
}
res
}
}