Overview
Top K problems ask for the k largest, smallest, most frequent, or closest items. The standard tool is a heap of size k: to keep the k largest, use a min-heap and evict the smallest whenever the heap grows past k. The heap's root is then the kth largest element.
This costs O(n log k) instead of O(n log n) for a full sort, and it works on streams where data never stops. Alternatives include quickselect (O(n) average) and bucket sort when values are bounded, such as frequencies.
There are only k chairs on stage. Each new contestant is compared with the weakest finalist; if they are better, the weakest leaves and the newcomer sits. The weakest finalist is always easy to find because the min-heap keeps them on top.
When to use it
- Phrases like k largest, k smallest, kth largest, top k frequent, k closest.
- Data arrives as a stream and you must report the current top k.
- n is large and k is small, so sorting everything is wasteful.
- Merging k sorted lists (heap of k list heads).
Problem patterns it solves
Recognize it when: a single order statistic.
- 215. Kth Largest Element in an Array
- 703. Kth Largest Element in a Stream
- 378. Kth Smallest Element in a Sorted Matrix
Recognize it when: most frequent elements or words.
- 347. Top K Frequent Elements
- 692. Top K Frequent Words
- 451. Sort Characters By Frequency
Recognize it when: closest points to origin, closest values to x.
- 973. K Closest Points to Origin
- 658. Find K Closest Elements
Recognize it when: merge k sorted lists or find the smallest pairs across arrays.
- 23. Merge k Sorted Lists
- 373. Find K Pairs with Smallest Sums
- 632. Smallest Range Covering Elements from K Lists
Recognize it when: repeatedly take the largest or smallest: stones, tasks, sticks.
- 1046. Last Stone Weight
- 621. Task Scheduler
- 1167. Minimum Cost to Connect Sticks
Where it is used in real software
Trending hashtags, top sellers, and game leaderboards keep the top K by score from streams of events.
Search engines score many candidate documents and keep only the top 10 to 100 with a bounded heap before final ranking.
Nearest-neighbor search in embedding databases returns the top K most similar vectors, maintained with a heap.
Top K slowest endpoints or noisiest customers in observability tools, often approximated with Count-Min Sketch plus a heap.
Key terms
- Min-heap of size k
- Keeps the k largest; the root is the kth largest.
- Max-heap of size k
- Keeps the k smallest; the root is the kth smallest.
- Quickselect
- Partition-based selection in O(n) average time.
- Bucket by frequency
- Index an array by count to extract top frequencies in O(n).
Heap of size k
- 1Choose the opposite heap
For the k largest, use a min-heap (so the weakest of the top k is on top to be evicted).
- 2Push each element
heap.push(x).
- 3Evict when too big
If heap.size > k, pop the root.
- 4Read the answer
The heap holds the top k; the root is the kth largest.
Kth largest with k = 3
nums = [3, 2, 1, 5, 6, 4]
| x | Heap after push | Evict? | Heap (min-heap, size <= 3) |
|---|---|---|---|
| 3 | [3] | no | [3] |
| 2 | [2, 3] | no | [2, 3] |
| 1 | [1, 2, 3] | no | [1, 2, 3] |
| 5 | [1, 2, 3, 5] | pop 1 | [2, 3, 5] |
| 6 | [2, 3, 5, 6] | pop 2 | [3, 5, 6] |
| 4 | [3, 4, 5, 6] | pop 3 | [4, 5, 6] |
NOWx: 3 | Heap after push: [3] | Evict?: no | Heap (min-heap, size <= 3): [3]
The heap holds the 3 largest values {4, 5, 6}, and its root, 4, is the 3rd largest. Each step is O(log k).
Implementation
// JavaScript has no built-in heap; this minimal MinHeap is interview-readyclass MinHeap { constructor(compare = (a, b) => a - b) { this.data = []; this.compare = compare; } get size() { return this.data.length; } peek() { return this.data[0]; } push(x) { const d = this.data; d.push(x); let i = d.length - 1; while (i > 0) { const p = (i - 1) >> 1; if (this.compare(d[i], d[p]) >= 0) break; [d[i], d[p]] = [d[p], d[i]]; i = p; } } pop() { const d = this.data; const top = d[0]; const last = d.pop(); if (d.length) { d[0] = last; let i = 0; while (true) { const l = 2 * i + 1, r = l + 1; let m = i; if (l < d.length && this.compare(d[l], d[m]) < 0) m = l; if (r < d.length && this.compare(d[r], d[m]) < 0) m = r; if (m === i) break; [d[i], d[m]] = [d[m], d[i]]; i = m; } } return top; }} function findKthLargest(nums, k) { const heap = new MinHeap(); for (const x of nums) { heap.push(x); if (heap.size > k) heap.pop(); } return heap.peek();} // 347: bucket sort by frequency, O(n)function topKFrequent(nums, k) { const freq = new Map(); for (const x of nums) freq.set(x, (freq.get(x) ?? 0) + 1); const buckets = Array.from({ length: nums.length + 1 }, () => []); for (const [value, count] of freq) buckets[count].push(value); const result = []; for (let f = buckets.length - 1; f > 0 && result.length < k; f--) { result.push(...buckets[f]); } return result.slice(0, k);}Complexity and performance
O(k) space.
Simple but wasteful for small k.
O(n^2) worst case; random pivot.
Frequencies are bounded by n.
N total nodes.
Trade-offs
Quickselect is faster on average for a one-off array but modifies it and does not work on streams. The heap handles streams and guarantees O(n log k).
A heap returns the top k unsorted; sort them at the end (O(k log k)) if order is required.
Variants and related techniques
A max-heap for the lower half and a min-heap for the upper half give the running median.
Top K Frequent Words breaks ties alphabetically; the comparator must reflect that in reverse for a min-heap.
In sorted matrices, binary search the answer value and count elements <= mid.
Common mistakes
- Using a max-heap to find the k largest.
Fix: That needs all n elements in the heap. A min-heap of size k is the efficient choice.
- Java PriorityQueue is a min-heap by default.
Fix: Use Collections.reverseOrder() or a comparator for a max-heap.
- Comparator subtraction overflow.
Fix: Use Integer.compare or Long for distances.
Interview questions
Why a min-heap for the k largest?
The root of a min-heap is the smallest of the k kept values, which is exactly the one to evict when a larger value arrives. This keeps the heap at size k.
Can you do better than O(n log k)?
Quickselect is O(n) on average. For frequencies, bucket sort is O(n) because counts range from 1 to n.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 703. Kth Largest Element in a Stream | Easy | Streaming heap. |
| 1046. Last Stone Weight | Easy | Max-heap simulation. |
| 215. Kth Largest Element in an Array | Medium | Heap vs quickselect. |
| 347. Top K Frequent Elements | Medium | Bucket sort. |
| 973. K Closest Points to Origin | Medium | Max-heap by distance. |
| 23. Merge k Sorted Lists | Hard | K-way merge. |