2Brute2Best
🔥0

Median of a Stream of Integers

Medium·GeeksforGeeksBasic Anchor
GeeksforGeeks
30-Second Mental ModelTwo Heaps — Running median (max-heap for the lower half, min-heap for the upper half)
Complexity:O(N² log N)→O(N log N)
Key Insight

Keep the numbers in two heaps. low is a max-heap that holds the smaller half, and high is a min-heap that holds the larger half. Each new number is pushed into low, then low's largest moves to high, and if high became bigger, its smallest moves back. The median is then low.top(), or the average of both tops.

Core Validity Invariant

Every value in low is ≤ every value in high, and low has the same size as high or one more. With both true, the two tops sit right next to the middle of the sorted list.

01

Problem

Numbers arrive one at a time, like a live feed. After each new number, you need the median of all the numbers seen so far.

The median is the middle value after sorting. If the count is odd, it is the middle number. If the count is even, it is the average of the two middle numbers.

Given arr, return a list of doubles. The i-th answer is the median of arr[0] … arr[i]. Whole-number medians are still returned as doubles, such as 4.0.

Input

An integer array arr. Think of it as a stream: element i arrives after elements 0 … i − 1.

Output

A vector<double> with one entry per input number. Entry i is the median of the first i + 1 numbers.

Example 1
Input: arr = [5, 15, 1, 3, 2, 8]
Output: [5.0, 10.0, 5.0, 4.0, 3.0, 4.0]

After 5 the median is 5. After 15, the two middle values are 5 and 15, so the median is 10. After 1, the sorted list [1, 5, 15] has middle 5. After 3, the list [1, 3, 5, 15] has middle pair 3 and 5, so the median is 4. After 2, the list [1, 2, 3, 5, 15] has middle 3. After 8, the list [1, 2, 3, 5, 8, 15] has middle pair 3 and 5, so the median is 4.

Example 2
Input: arr = [2, 2, 2, 2]
Output: [2.0, 2.0, 2.0, 2.0]

Every prefix contains only 2s, so every median is 2.

Constraints
  • • Each value fits in a 32-bit int (the function takes a `vector<int>`).
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    When one new number arrives, does the median move a lot, or only a little? What part of the old answer can I reuse?

  2. 2.

    To find the median of 5 numbers, do I need all 5 in sorted order, or only the one or two in the middle?

  3. 3.

    If I kept the numbers in sorted order, where would a new number go, and how many numbers would have to move?

  4. 4.

    Split the sorted numbers into a lower half and an upper half. Which two numbers sit on the boundary between them?

  5. 5.

    Which data structure can hand me its largest value fast, and which one can hand me its smallest value fast?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceAfter each number, copy the numbers so far, sort the copy, and read the middleO(N² log N)O(N)
BetterFind each number's slot with binary search and insert it; the median is read from the middle indexO(N²)O(N)
OptimalLower half in a max-heap, upper half in a min-heap; the two tops sit next to the medianO(N log N)O(N)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “median of a stream”The middle of the sorted numbers, but we never need them all in order. Only the boundary between the two halves matters.
  • “after each new number”We must answer at every step, so each step has to be fast. Re-sorting from scratch is too slow.
  • “running”The answer changes a little each step. Keep both sides ready so each change is a heap move.
Numbers arrive one at a time+answer needed after every arrival+median = the tops of two halves→Two Heaps — Running median (max-heap for the lower half, min-heap for the upper half)

The median only needs the two numbers next to the middle, so keep those two tops ready at all times. The rule for this problem is the size rule plus the order rule: every low value ≤ every high value, and low is the same size as high or one bigger. Find Median from Data Stream uses the same rule, but splits the work between addNum and findMedian. Sliding Window Median also removes numbers, which needs lazy deletion or a multiset on top of the heaps.

10

Don't make this mistake

Pattern confusion: always push into low and only fix the sizes
✗ low.push(x); if (low.size() > high.size() + 1) { high.push(low.top()); low.pop(); }
✓ low.push(x); high.push(low.top()); // move the largest across, every time low.pop(); if (high.size() > low.size()) { low.push(high.top()); high.pop(); }

This looks like the two-heap idea, but it never moves a value across unless the sizes are off. Dry run on [1, 6, 100, 3, 50, 2]: after 1 and 6 the code is right (median 3.5). After 100, low is {1, 100} and high is {6}. The sizes differ by 1 with low bigger, so nothing moves, and the code returns 100. The right median is 6. The 100 is stuck in low, above high's 6, which breaks the order rule. Step 5 fails the same way: after 50 it returns 50 instead of 6.

Comparator direction: high declared as a max-heap
✗ priority_queue<int> high; // max-heap by default
✓ priority_queue<int, vector<int>, greater<int>> high; // min-heap

A plain priority_queue<int> returns its largest value first. Dry run on [1, 6, 100, 3, 50, 2]: after 100 the code moves 100 into high. Then the size step takes high's top, which is now 100, and moves it back to low. low is {1, 100} and the answer is 100 instead of 6. After 3 the answer is 51.5 instead of 4.5. The top of the upper half must be its smallest.

Even count: averaging with int division
✗ return (low.top() + high.top()) / 2; // int / int
✓ return (low.top() + (double)high.top()) / 2.0;

Both tops are ints, so C++ divides them as ints and drops the fraction. Dry run on [1, 6, 100, 3, 50, 2]: after 6 the middle pair is 1 and 6, and (1 + 6) / 2 gives 3, but the median is 3.5. After 3, the code gives 4 instead of 4.5. Cast to double before the division.

11

Want to implement this?

Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Two Heaps translate into production architectures and low-level memory mechanics.