Top-K with a heap
Top-K selection with a bounded PriorityQueue, K largest and smallest, frequency, closest points, Kth largest, streaming feeds, complexity and edge cases.
On this page
🏆 What is Top-K with a heap?
Top-K means keeping only the K best candidates from a larger input: the 10 largest transactions, 100 most frequent words, or 5 closest points. A heap solves it by keeping a small "winners so far" area instead of sorting the whole input. It acts like a nightclub door with K seats inside: once the room is full, the weakest person inside is the one who gets replaced.
For this lesson, we'll focus on the Top-K pattern, not heap internals. We'll use Java's PriorityQueue as a bounded heap, cover K largest, K smallest, Top-K by frequency, K closest points, Kth largest and streaming feeds, then compare heap, sort and quickselect honestly. If you need the array layout, sift-up, sift-down and comparator rules first, read PriorityQueue and binary heaps.
Below the line (out of scope)
- Binary heap internals: PriorityQueue and binary heaps
- Frequency maps before Top-K frequency: Frequency counting and deduplication
- Grouping before per-key summaries: Grouping and partitioning
- Full quickselect implementation is a selection algorithm topic, so here we compare it and name the trade-off.
The 30-second answer
For K largest values, keep a size-K min-heap. The root is the smallest value among the current winners, so every new value only has to beat peek() to enter. The simple implementation is offer(x); if (heap.size() > k) poll();, which costs O(n log k) and O(k) space. A slightly better version fills the heap, then only does poll plus offer when x > heap.peek(), so small losers are discarded in O(1). Sorting costs O(n log n), quickselect is O(n) average but mutates or partitions the input and returns an unsorted frontier. Heap order is not result order, so sort the final K values if the output contract needs it.
What you’ll learn
- Maintain a size-K min-heap for K largest values and explain the eviction invariant
- Compare
offer-then-pollwith thepeek-compare-replace optimization - Choose among heap, full sort and quickselect using O(n log k), O(n log n) and O(n) average trade-offs
- Implement K smallest with a max-heap using
Comparator.reverseOrder() - Solve Top-K by frequency, K closest points, Kth largest and streaming Top-K variants
- State edge cases for invalid K, duplicates, ties and result ordering
01Picture it first: a tiny winners room
Imagine a live leaderboard with room for 3 scores. The room is a min-heap, so the lowest score inside stands at the door. A new score that is not higher gets turned away; a higher score enters and the old lowest score leaves.
That is why the heap direction feels backwards at first. For K largest, the heap root is the loser among the winners.
The stream 5, 1, 9, 3, 7 fills a size-3 min-heap, then 3 evicts 1 and 7 evicts 3, leaving top 3 values 9, 7 and 5
Notice what we are not doing. We are not keeping every score, and we are not maintaining a fully sorted list of winners after every item. We maintain just enough order to know which retained candidate is easiest to evict.
02Top-K under the hood: size-K min-heap
Try it yourself first
Before reading the code, process 5, 1, 9, 3, 7 with k = 3. Which value is evicted when 7 arrives?
Here is the compact version you will see in many solutions: offer every number, then evict when the heap grows past K.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
final class TopKLargestSimpleDemo {
static List<Integer> topKLargest(int[] numbers, int k) {
if (k <= 0) return List.of();
PriorityQueue<Integer> heap = new PriorityQueue<>();
for (int number : numbers) {
heap.offer(number);
if (heap.size() > k) {
heap.poll();
}
}
List<Integer> result = new ArrayList<>(heap);
result.sort(Collections.reverseOrder());
return result;
}
public static void main(String[] args) {
System.out.println(topKLargest(new int[] {5, 1, 9, 3, 7}, 3)); // [9, 7, 5]
}
}
Notice three things:
- The heap never holds more than
k + 1elements, and after the eviction it holds at most K. - Duplicates count as separate values. If the input is
{9, 9, 8}andk = 2, the answer is[9, 9]unless the problem says distinct. - The result is explicitly sorted because iterating a
PriorityQueueis heap order, not sorted order.
The slightly better version avoids heap writes for values that cannot enter the top K. Once the heap is full, compare with peek() first.
Premium lesson
Keep reading with the Java Pass
The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.
- Why O(n log k) matters, and when it doesn't
- Variations: smallest, frequency, closest and Kth largest
- Streaming Top-K over an unbounded feed
- Advanced: edge cases and comparator traps
- How to say it in the interview
From ₹199 · one-time payment · No auto-renewal