An interactive visualization of how two heaps (a max-heap and a min-heap) maintain the running median as numbers stream in. Watch the heaps rebalance after every insertion.
Heap / Priority Queue LeetCode 295 ↗ HardaddNum(num) — Add an integer num from the data stream to the data structure.findMedian() — Return the median of all elements so far.[1, 2, 3], the median after each add is 1, 1.5, 2.
import java.util.PriorityQueueclass MedianFinder { private val lo = PriorityQueue<Int>(compareByDescending { it }) private val hi = PriorityQueue<Int>() // min-heap fun addNum(num: Int) { // max-heap lo.add(num) hi.add(lo.poll()) if (hi.size > lo.size) { lo.add(hi.poll()) } } fun findMedian(): Double { if (lo.size > hi.size) return lo.peek().toDouble() return (lo.peek() + hi.peek()) / 2.0 }}
Keep two heaps: a max-heap (lo) storing the smaller half of the numbers,
and a min-heap (hi) storing the larger half.
The max-heap’s top is the largest element in the left half, and the min-heap’s top is the smallest in the right half.
The median is always at the boundary between the two heaps.
lo (the max-heap, stored with negated values in Python).lo and push it onto hi. This ensures the largest element from the left half moves to the right half if needed.hi has more elements than lo, pop the min of hi and push it back onto lo. This maintains the invariant that lo always has equal or one more element than hi.lo has more elements, the median is the top of lo. Otherwise, it is the average of the tops of both heaps.
Each addNum performs at most three heap operations (push/pop), each costing O(log n).
Finding the median is a constant-time peek at the top of one or both heaps.
All n elements are stored across the two heaps, so space is O(n).