Design a streaming median structure
Company: Amazon
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This interview question evaluates algorithm design, data structures, correctness, complexity, edge cases, and implementation details in a realistic interview setting. A strong answer for Design a streaming median structure states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Constraints
- 1 <= number of operations <= 10^6
- -10^9 <= num <= 10^9
- median() may be called on an empty stream (return None / null)
- Duplicates are allowed; both even and odd total counts must be handled
Examples
Input: ([['add', 1], ['add', 2], ['median'], ['add', 3], ['median']],)
Expected Output: [None, None, 1.5, None, 2.0]
Explanation: After 1,2 the median is (1+2)/2 = 1.5 (even count). After adding 3, the median of {1,2,3} is 2.0 (odd count).
Input: ([['median']],)
Expected Output: [None]
Explanation: Median of an empty stream is undefined, so None is returned.
Input: ([['add', 5], ['median']],)
Expected Output: [None, 5.0]
Explanation: Single element: the median is the element itself, 5.0.
Input: ([['add', 2], ['add', 2], ['add', 2], ['median']],)
Expected Output: [None, None, None, 2.0]
Explanation: Duplicates are handled; the median of {2,2,2} is 2.0.
Input: ([['add', -1], ['add', -2], ['add', -3], ['median'], ['add', -4], ['median']],)
Expected Output: [None, None, None, -2.0, None, -2.5]
Explanation: Negatives and out-of-order inserts: {-1,-2,-3} median -2.0; after adding -4, {-4,-3,-2,-1} median is (-3 + -2)/2 = -2.5.
Input: ([['add', 6], ['add', 10], ['add', 2], ['add', 6], ['add', 5], ['median']],)
Expected Output: [None, None, None, None, None, 6.0]
Explanation: Unordered stream with a duplicate; sorted {2,5,6,6,10} has middle element 6.0.
Hints
- Maintain two heaps: a max-heap for the smaller half and a min-heap for the larger half, keeping their sizes balanced to within one element.
- On add(), push to the correct half based on the current max-heap top, then move one element across if the size invariant breaks — this keeps the operation O(log n).
- On median(), if the heaps are equal size average the two tops; otherwise the larger heap's top is the median. This reads in O(1).