Top K Frequent Elements

LeetCode 347 · View on LeetCode

Given an integer array nums and an integer k, return the k most frequent elements. The answer is guaranteed to be unique.


Solution 1: Bucket Sort — O(n)

Use frequency as an index. Since no element appears more than n times, create buckets of size n+1 and walk from highest frequency down.

package main

import "fmt"

func topKFrequent(nums []int, k int) []int {
	freq := map[int]int{}
	for _, n := range nums {
		freq[n]++
	}

	// buckets[i] holds numbers that appear exactly i times
	buckets := make([][]int, len(nums)+1)
	for num, count := range freq {
		buckets[count] = append(buckets[count], num)
	}

	result := []int{}
	for i := len(buckets) - 1; i >= 0 && len(result) < k; i-- {
		result = append(result, buckets[i]...)
	}
	return result
}

func main() {
	fmt.Println(topKFrequent([]int{1, 1, 1, 2, 2, 3}, 2)) // [1 2]
	fmt.Println(topKFrequent([]int{1}, 1))                  // [1]
}

Time: O(n) — one pass to count, one pass to bucket, one pass to collect. Space: O(n) — frequency map + buckets.


Solution 2: Min-Heap — O(n log k)

Maintain a min-heap of size k. For each unique element, push it onto the heap. If the heap exceeds size k, pop the least frequent — this ensures only the top k remain.

package main

import (
	"container/heap"
	"fmt"
)

type Item struct{ num, count int }
type MinHeap []Item

func (h MinHeap) Len() int            { return len(h) }
func (h MinHeap) Less(i, j int) bool   { return h[i].count < h[j].count }
func (h MinHeap) Swap(i, j int)        { h[i], h[j] = h[j], h[i] }
func (h *MinHeap) Push(x interface{})  { *h = append(*h, x.(Item)) }
func (h *MinHeap) Pop() interface{} {
	old := *h
	x := old[len(old)-1]
	*h = old[:len(old)-1]
	return x
}

func topKFrequent(nums []int, k int) []int {
	freq := map[int]int{}
	for _, n := range nums {
		freq[n]++
	}

	h := &MinHeap{}
	for num, count := range freq {
		heap.Push(h, Item{num, count})
		if h.Len() > k {
			heap.Pop(h)
		}
	}

	result := make([]int, h.Len())
	for i := len(result) - 1; i >= 0; i-- {
		result[i] = heap.Pop(h).(Item).num
	}
	return result
}

func main() {
	fmt.Println(topKFrequent([]int{1, 1, 1, 2, 2, 3}, 2)) // [1 2]
	fmt.Println(topKFrequent([]int{1}, 1))                  // [1]
}

Time: O(n log k) — each push/pop is O(log k), done for each unique element. Space: O(n) — frequency map + heap of size k.


Solution 3: Sort by Frequency — O(n log n)

The simplest approach: collect unique elements, sort them by frequency descending, take the first k.

package main

import (
	"fmt"
	"sort"
)

func topKFrequent(nums []int, k int) []int {
	freq := map[int]int{}
	for _, n := range nums {
		freq[n]++
	}

	unique := make([]int, 0, len(freq))
	for num := range freq {
		unique = append(unique, num)
	}

	sort.Slice(unique, func(i, j int) bool {
		return freq[unique[i]] > freq[unique[j]]
	})

	return unique[:k]
}

func main() {
	fmt.Println(topKFrequent([]int{1, 1, 1, 2, 2, 3}, 2)) // [1 2]
	fmt.Println(topKFrequent([]int{1}, 1))                  // [1]
}

Time: O(n log n) — dominated by the sort. Space: O(n) — frequency map + unique slice.


Comparison

Approach Time Space Notes
Bucket sort O(n) O(n) Optimal. Uses frequency as array index
Min-heap O(n log k) O(n) Good when k is small. Streaming-friendly
Sort O(n log n) O(n) Simplest code. Fine for small inputs
▶ Open Go Playground

Copy the code above and paste to run

© 2026 ByteLearn.dev. Free courses for developers. · Privacy