Kth Largest in a Stream: The Persistent Bounded Heap
"Kth Largest Element in a Stream" is a Easy-level staple in Amazon, Meta, Databricks loops, and it is a textbook fit for the Top-K and Heaps pattern — one of the nine patterns that cover the bulk of what FAANG coding interviews actually test. Part 3 of 11 in the Top-K and Heaps arc.
The Problem
Design a class initialized with k and an initial array, whose add(val) method appends a value and returns the k-th largest seen so far (duplicates count). The streaming version of Kth Largest — and the cleanest proof of why the bounded-heap formulation is the right one to internalize.
KthLargest(3, [4, 5, 8, 2])
add(3) -> 4; add(5) -> 5; add(10) -> 5; add(9) -> 8
Recognizing the Top-K and Heaps Pattern
When a problem asks for the k largest, smallest, closest, or most frequent — or for repeated access to an extreme while data changes — a heap gives O(log n) insertion and O(1) access to the extreme. The signature trick: keep a bounded heap of size k with the opposite polarity (a min-heap to track the k largest), evicting the root on overflow. Python's heapq is a min-heap; negate values for max behavior.
A stream forbids re-sorting per query. The size-k min-heap is a persistent summary: it holds exactly the k largest so far, its root is the running answer, and each update costs O(log k). When state must survive across calls, the heap is the class.
The Approach
Constructor: heapify the seed array, pop down to k elements. add: push, pop if over k, return the root. Guaranteed at least k elements by the time add is called per the problem contract — but pushing first keeps even that assumption unnecessary.
The heapq.heappushpop fusion (push then pop in one O(log k) operation) is the polish move when the heap is already full — name it, use it if comfortable.
Python Solution
import heapq
class KthLargest:
"""Streaming k-th largest via a persistent size-k min-heap."""
def __init__(self, k: int, nums: list[int]) -> None:
self.k = k
self.heap = list(nums)
heapq.heapify(self.heap)
while len(self.heap) > k:
heapq.heappop(self.heap)
def add(self, val: int) -> int:
heapq.heappush(self.heap, val)
if len(self.heap) > self.k:
heapq.heappop(self.heap)
return self.heap[0]
Complexity
- Time: O(log k) per add — one bounded push and at most one pop
- Space: O(k) — the heap never exceeds k + 1 momentarily
Interview Tips and Follow-Ups
- Explain why a max-heap is wrong here despite 'largest' in the title — you need cheap access to the smallest of the top k. This inversion is the pattern's core idea.
- Constructor cost O(n + (n−k) log n) via heapify-then-pop vs O(n log k) via repeated add — worth one sentence if asked.
- Real-system version: top-k metrics over sliding windows adds eviction by time — say how the heap alone stops sufficing (lazy deletion or a different sketch).
If this clicked, continue the Top-K and Heaps arc in the Technical Interview category. One hundred questions, nine patterns, all in Python.
Keep reading
Find Median From a Data Stream With Two Heaps
The two-heap balance: max-heap low half, min-heap high half. Python solution and complexity analysis for the heap and top-k interview pattern.
K Closest Points to Origin Without Square Roots
Bounded max-heap on squared distance — monotone transforms are free. Python solution and complexity analysis for the heap and top-k interview pattern.
Find K Pairs With Smallest Sums: Frontier Expansion
Explore an implicit sorted matrix — seed one row, expand neighbors lazily. Python solution and complexity analysis for the heap and top-k interview pattern.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.