Find Median from Data Stream
hardTests passed 2026-11-11v1.0.01. Core Invariant / The Trick
Maintain two balanced heaps: `lo` (max-heap of lower half) and `hi` (min-heap of upper half). Preserve two invariants on every `addNum`: (1) `max(lo) <= min(hi)`, and (2) `len(lo) >= len(hi)` differing by at most 1. Cleanest 3-step push: push into `lo`, pop `max(lo)` to `hi`, and if `len(hi) > len(lo)` pop `min(hi)` back to `lo`.
2. Complexity Bounds & Proof
Three-step push guarantees ordering and size invariants without conditional branches on comparison; `findMedian` is O(1).
3. Minimal Idiomatic Code
class MedianFinder:
def __init__(self):
self.lo = [] # max-heap via negation
self.hi = [] # min-heap
def addNum(self, num: int) -> None:
heapq.heappush(self.lo, -num)
heapq.heappush(self.hi, -heapq.heappop(self.lo))
if len(self.hi) > len(self.lo):
heapq.heappush(self.lo, -heapq.heappop(self.hi))
def findMedian(self) -> float:
if len(self.lo) > len(self.hi):
return float(-self.lo[0])
return (-self.lo[0] + self.hi[0]) / 2.04. Failure Modes & Interview Follow-ups
Pitfalls:- Comparing new value directly against heap tops creates fragile branching.
- Integer division `(lo[0] + hi[0]) / 2` in C++/Java without `.0` / `2.0` truncates `.5`.
Follow-ups:- If all numbers are in `[0, 100]`, use a 101-bucket counting array for O(1) `findMedian`.
Personal Notes & Scratchpad (Local-First Yjs CRDT)
Saved instantaneously in IndexedDB. Streams live across peers via Hocuspocus when signed in.
Related Invariants
Browser Scratchpad
Console Output
Click Run or press Cmd/Ctrl+Enter to execute locally in a Web Worker.