Katkat

Maintain the Median of a Data Stream

XiaopengSoftware Engineer · Technical Screen

Last updated

This problem tests the ability to maintain dynamic statistics in a data stream using efficient data structures to achieve optimal insertion and retrieval times.

Problem Statement

Design a data structure that reads a stream of integers one by one and returns the current median of all elements read so far after each insertion.

If the number of elements is odd, the median is the middle element in the sorted list. If the number of elements is even, the median is the average of the two middle elements.

Implement the MedianFinder class:

class MedianFinder:
    def __init__(self):
        """Initialize the data structure."""

    def add_num(self, num: int) -> None:
        """Adds an integer from the data stream to the data structure."""

    def find_median(self) -> float:
        """Returns the median of all elements so far."""

Constraints

  • add_num will be called up to 50,000 times.
  • find_median will be called up to 50,000 times.
  • Integer values are within the range [-10^5, 10^5].

Examples

Example 1

MedianFinder mf = new MedianFinder();
mf.add_num(1);
mf.add_num(2);
mf.find_median(); // returns 1.5 ( (1+2)/2 )
mf.add_num(3);
mf.find_median(); // returns 2.0

Edge Cases

  • Stream with a single element.
  • Stream with duplicate elements.
  • Stream where all elements are the same.

Hints

Hint 1

Consider using two heaps: a max-heap to store the smaller half of the numbers and a min-heap to store the larger half.

Hint 2

Ensure the size difference between the two heaps is at most 1 at all times to keep the middle elements at the roots.

Hint 3

When adding a number, check if it belongs in the max-heap or min-heap, then rebalance the heaps if the size property is violated.

Follow-up questions

  • How would you modify your solution if the stream consists of billions of integers and you cannot store all of them in memory?
  • If you only need to return the median of the last 10,000 elements (a sliding window), how would your approach change?
  • What would be the impact on performance if the input values were guaranteed to be in a very small range (e.g., 0 to 100)?