skip to content

questions

18

How does a min-heap merge k sorted input streams into one ordered output stream?

level: juniorimportance: must knowfreq 74%

answer

  1. how many candidates can be the next output?
  2. one live element per source at a time
  3. the heap holds k entries, never N
  4. each entry remembers which source it came from
  5. extract smallest, then refill from that same source

basics

~20 s

Keep only the current head of each of the k streams in a min-heap. Repeatedly extract the smallest, emit it, and push that same stream's next element in its place. The heap never grows beyond k entries.

solid answer

~50 s

The insight is that the next element of the merged output can only be the current head of one of the k streams, so you never need more than k candidates in flight. Seed a min-heap with one entry per stream, each entry carrying the value plus the identifier of the stream it came from. Then loop: extract the minimum, emit its value, and push the successor from that same stream. The source identifier is what makes the refill possible — without it you know the winning value but not where to pull the next candidate. With N elements total, every element is inserted once and extracted once from a heap of size at most k, giving `O(N log k)` time and `O(k)` extra space. Crucially the input is consumed lazily: you hold k elements, not N, so streams larger than memory still merge.

go deeper

for a junior

Be ready to state the loop out loud: seed the heap with one head per source, extract the minimum, emit it, push the successor from that same source. Say why the heap size is k and not the total element count.

for a middle

Explain why the next output element can only be one of the k heads, and derive the O(N log k) bound from one insert and one extract per element. Point out that the source identifier is what makes the refill step possible.

for a senior

Show the operational value: bounded memory and incremental output mean you can merge feeds far larger than RAM and let a consumer read before the inputs finish. Note where per-source read buffering, not the heap, dominates memory.

for a principal

Own the framing that this pattern converts a memory-bound sort into a streaming pipeline. Be ready to argue when a merge belongs in the data path at all versus pushing ordering upstream to the producers or an index.

## The problem shape You operate a fleet of 200 servers. Each one writes its own log file, and each file is already in timestamp order because each server appends as events happen. Now you want a single chronological feed across the whole fleet for incident review. You have 200 sorted sequences and want one sorted sequence — that is the k-way merge, with k = 200. ## The key observation At any moment, what is the next line of the merged feed? It must be the oldest line that has not been emitted yet. Because every source is internally sorted, the oldest unemitted line of any source is that source's *current head*. So the global next line is the minimum over just k values — one per source — not a minimum over all N remaining lines. That single observation is the whole pattern. You never need more than k live candidates, and a min-heap is exactly the structure that gives you "smallest of k" repeatedly while accepting replacements cheaply. ## The loop 1. **Seed.** For each source i, take its first element and insert it into the min-heap. Each heap entry is a composite record: the ordering value (here, the timestamp), the source identifier i, and the position within that source. 2. **Extract.** Pull the minimum out of the heap. That value is the next element of the merged output; emit it. 3. **Refill.** The extracted entry came from source i. Take the *next* element of source i and insert it. If source i has nothing left, insert nothing — the heap simply shrinks. 4. **Repeat** until the heap is empty. An empty heap means every source has been drained. At every point the heap holds at most one entry per source, so its size is bounded by k, and it starts at k and only shrinks as sources run dry. ## Why the source identifier matters A beginner version stores only the values. Then the extraction tells you *what* the smallest value was but not *which* source produced it, so you cannot fetch its successor — and if you re-scan the sources to find out, you have thrown away the entire advantage. Storing the source identifier (and, if the source is not itself a cursor you can advance, the position within it) is not a decoration; it is the mechanism. ## The cost Every one of the N elements enters the heap exactly once and leaves exactly once. Each of those two operations costs `O(log k)` because the heap holds at most k entries. Total: `O(N log k)` time. Extra space is `O(k)` for the heap itself, plus whatever buffering each source needs. Compare the naive alternative of concatenating all 200 files and sorting the result: that is `O(N log N)` comparisons and, worse, it requires all N lines resident at once. With 200 servers' worth of logs, N is enormous and k is 200. `log k` is about 8 while `log N` might be 30, and the memory difference is the difference between "runs on a laptop" and "does not run". ## What the pattern buys beyond speed - **Streaming.** Output is produced incrementally. The consumer can start reading the merged feed before the inputs have been fully read, and you can stop early if you only wanted the first few thousand lines. - **Bounded memory.** Memory depends on k and the per-source buffer size, not on the data volume. This is precisely why the pattern underpins merging phases in disk-based sorting: the whole dataset never has to fit. - **Order preservation within a source.** Because a source's next element only enters the heap after its predecessor has left, elements of one source can never be emitted out of order relative to each other. ## Recognising it in an interview Interviewers rarely say "use a heap". They say: "you have many already-sorted feeds and need one merged feed", or "give me the smallest values across many sorted sequences without materialising everything". Both descriptions are the same machine: heap of heads, extract, emit, refill. The moment you hear *many* sorted inputs and *one* sorted output, size the heap at k, not at N, and remember to tag each entry with where it came from. A final calibration: when k is small — two or three sources — the heap is technically correct but constant factors make a direct comparison of the heads simpler and faster. The heap earns its keep when k is large enough that scanning all k heads on every emitted element would itself dominate.

  • Why does each heap entry have to carry its source identifier?
    Because the refill step is source-specific. After extracting the minimum you must push the successor from the very source that just lost its head, and nothing else about the extracted value tells you which one that was. Without the identifier you would have to rescan all k sources to find the successor, which turns an `O(log k)` step into an `O(k)` one and destroys the bound.
  • What does the heap approach give you that concatenating everything and sorting does not?
    Two things. Cost: `O(N log k)` instead of `O(N log N)`, and with many sources k is far smaller than N. More importantly, memory: sorting the concatenation needs all N elements resident, while the merge holds only k heads plus per-source buffers. That is what lets you merge inputs far larger than available memory and start emitting output immediately instead of after the last input is read.
  • If k is only 2, is the heap still the right tool?
    Correct, but overkill. With two sources `log k` is 1, so the asymptotic bound is the same as simply comparing the two heads directly, and the heap adds allocation and bookkeeping constants for nothing. The heap starts paying off when k is large enough that scanning every head on each emitted element would itself dominate the runtime.

Two hundred queues of people, each queue already ordered by arrival time. You only ever compare the 200 people standing at the front; when one is let through, only that queue steps forward.

saying these in an interview costs you the question

  • Puts all N elements into one heap instead of k heads
  • Stores only values, so the successor cannot be fetched
  • Claims the merge is O(N log N) regardless of k
  • Assumes all inputs must be fully loaded before merging
  • Re-sorts the whole output after merging to be safe

context

open as a page

Why must a size-k heap that keeps the k largest values be a min-heap rather than a max-heap?

level: juniorimportance: must knowfreq 78%

basics

~20 s

The heap must be a min-heap because its root is the smallest of the k values you are still keeping — the bar a new value must beat. A max-heap would evict the largest values and leave you the k smallest.

open as a page

Why does a running median over a live stream use two heaps rather than one sorted buffer?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A max-heap holds the lower half of the samples and a min-heap the upper half, so the median sits at the heap tops: O(1) to read, O(log n) to absorb a new sample. A sorted buffer costs O(n) per insert to shift elements.

open as a page

Finding the 100 cheapest of 10 million products: sort, size-k heap, or quickselect?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Sorting the whole catalog costs O(n log n) to answer a question about 100 items. A retained-candidate heap does one pass in O(n log k) with O(k) memory; quickselect averages O(n) but rearranges the input and needs it all resident.

open as a page

Why is heap-based k-way merge O(N log k) but merging the k sources pairwise in a loop O(N*k)?

level: middleimportance: must knowfreq 66%

basics

~20 s

The heap touches each element twice, at log k cost each. Merging source after source into one growing accumulator re-copies everything already accumulated on every round, so the earliest elements are copied about k times.

open as a page

With n = 100 million readings and k = 100, what does a size-k heap actually save over sorting?

level: middleimportance: must knowfreq 72%

basics

~20 s

Roughly a fourfold smaller log factor: log2(100) is about 6.6 against about 26.6 for 100 million. The real saving is elsewhere — 100 resident values instead of 100 million, in a single forward pass over data of unknown length.

open as a page

In a two-heap running median, what invariant holds after every insert, and how is it restored?

level: middleimportance: must knowfreq 62%

basics

~20 s

Every value in the max-heap is at most every value in the min-heap, and the two sizes differ by at most one. A single pop-and-push, moving one top from the heavier heap to the lighter one, restores the size part after any insert.

open as a page

Quickselect runs in expected O(n) — why isn't it the default way to pick the k smallest?

level: middleimportance: must knowfreq 60%

basics

~20 s

Expected O(n) is an average over pivot choices, not a per-call guarantee: naive pivot rules degrade to O(n^2) on sorted or duplicate-heavy input. Quickselect also permutes the caller's data in place and needs the entire input resident.

open as a page

In a heap-based k-way merge, which two boundary conditions crash the naive loop?

level: middleimportance: should knowfreq 48%

basics

~20 s

Seeding from a source that is empty, and refilling from a source that has just run out. Both read past the end of a sequence. Guard the seed loop with an emptiness check and the refill with a has-next check.

open as a page

In a k-way merge heap, what ordering is guaranteed among equal keys from different sources?

level: seniorimportance: should knowfreq 44%

basics

~20 s

None. A heap is not stable, so equal keys from different sources come out in an order determined by internal array positions. Order within a single source is preserved automatically; across sources you must extend the comparison key to get determinism.

open as a page

In frequency top-50 over 10 million distinct terms, where does the memory actually go?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Almost all of it goes to the counting phase. Ranking terms by frequency needs a count for every one of the 10 million distinct terms held at once; the size-50 heap adds fifty entries. The heap bounds the output, not the memory.

open as a page

Why does a two-heap running median report a far-too-low value if rebalancing only shrinks the max-heap?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Repairing only the max-heap-too-large case lets the min-heap grow without limit whenever samples arrive above the current median, so the max-heap keeps an old small value on top and the reported median sinks toward it. Both repair directions are required.

open as a page

How do you keep a two-heap median over a fixed trailing window when the expiring sample isn't at a top?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Heaps remove only their top, so expiring samples are deleted lazily: mark the departing value as pending removal, track logical sizes separately from physical heap sizes, rebalance on the logical counts, and discard stale tops before reading the median.

open as a page

Sort, size-k heap, or quickselect — which survives an unbounded stream of price updates?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Only the bounded candidate heap survives. It sees each record once and holds O(k) state, so an answer is available at any moment. Sorting and quickselect are offline: both need the entire input materialized with random access.

open as a page

What does a size-k heap commit you to on a memory-capped gateway ingesting an unbounded sensor stream?

level: principalimportance: should knowfreq 40%

basics

~20 s

A size-k heap commits you to one frozen question. Bounded state and a single pass let the job run under the cap, but every value that lost to the bar is destroyed, so a different k or metric means re-ingesting the stream.

open as a page

Top-k becomes a user-tunable parameter up to the full catalog — which selection strategy do you commit to?

level: principalimportance: should knowfreq 35%

basics

~20 s

Commit to one default with a documented, measured threshold rather than three tuned paths. As k approaches n, O(n log k) converges on O(n log n) and the candidate structure holds O(n) items — above the crossover, just sort.

open as a page

How do you choose merge fan-in k when merging thousands of sorted streams under a memory ceiling?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

Memory bounds the fan-in, not comparison cost. Comparisons grow as log k, but every open source needs a resident read buffer, so memory grows linearly in k. Take the largest k whose per-source buffers still read efficiently.

open as a page

When would you not keep an exact two-heap median for per-endpoint latency across a large fleet?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

An exact two-heap median keeps every sample forever, so memory grows without bound per endpoint per instance, and two instances' results cannot be combined into a global median. Under a fleet memory ceiling, prefer a bounded window or a mergeable quantile sketch.

open as a page