Katkat

Streaming Top-K Frequent Elements with O(1) Updates Instead of a Heap

NVIDIASoftware Engineer · Onsite

Last updated

Design a structure that consumes an unbounded stream and reports the K most frequent elements at any time, first with a heap and then with constant-time updates after the interviewer rejects the heap. It tests per-operation cost analysis, data-structure invariants, deterministic tie handling, and extensions to sliding windows, approximate counting, and sharded streams.

Elements arrive one at a time from an unbounded stream (for example, item IDs from an event log). Design a data structure that consumes the stream and can report, at any moment, the K elements that have appeared most often so far. Pseudocode is acceptable, but every operation's cost must be stated.

The structure supports two operations:

  • add(x): record one more occurrence of element x.
  • top_k(k): return up to k elements with the highest occurrence counts so far, most frequent first.

After you present a heap-based solution, the interviewer says they are not satisfied with it and pushes you to make processing each arriving element faster.

Constraints and Clarifications

  • "Top K" here means by occurrence count, not by element value.
  • Elements are hashable IDs, and one counter per distinct element fits in memory.
  • Counts only grow: there are no deletions and no time window unless a follow-up introduces one.
  • If fewer than k distinct elements have been seen, top_k(k) returns all of them.

Clarifying Questions

  • How should elements with equal counts be ordered in the result?
  • Is K fixed when the structure is created, or can every query ask for a different k?
  • Roughly how many add calls arrive per top_k call? That decides whether the work should go on the write side or the read side.
  • Must the answer be exact, or is an approximation acceptable if the number of distinct elements grows beyond memory?

Part 1 — A heap-based design

Design the structure with a hash map and a heap. Give the time cost of add and of top_k, and the memory cost, in terms of the number of distinct elements D and K.

What This Part Should Cover

  • A correct heap-based design, including how an element already in the heap gets its count updated
  • Per-operation time costs and memory
  • Why the design is correct as counts change

Part 2 — Faster than a heap

The interviewer wants the per-element cost below what a heap gives. Design a structure where add(x) takes O(1) time and top_k(k) takes time proportional to k, and explain why each operation meets that bound.

What This Part Should Cover

  • A data structure whose updates touch only a constant number of nodes
  • The invariants that keep the structure correct, including what happens to groups that become empty
  • A query that stops after k elements without scanning unrelated state
  • A deterministic tie rule, and a small worked trace

Hints

Hint 1

Where does the heap live: Decide whether the heap is built when a query arrives or kept up to date on every `add`, and compare what each choice costs per operation.

Hint 2

How far can one add move an element: A single `add` raises exactly one count by exactly one. Think about what that means for where the element sits relative to elements with other counts.

Follow-up questions

  • Counts should cover only the last hour of events. What must change, and can updates stay O(1)?
  • The number of distinct elements is far larger than memory. How do you report an approximate top K, and what error guarantee can you give?
  • The stream is split across many machines. How do you compute an exact global top K, and when is merging each machine's local top K wrong?
  • If "top K" meant the K largest values seen so far rather than the most frequent, how would the design change?