Maintain streaming median and loosemedian
Company: Google
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 Maintain streaming median and loosemedian states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Constraints
- 1 <= len(nums)
- All values are positive integers (x >= 1), so log2(median) is always defined and the loose-median interval exists.
- Median may be a non-integer (.5) when the count is even.
- Compute 2^k with a bit shift (1 << k); guard log2 against floating-point error near powers of two.
Examples
Input: ([3, 4, 5],)
Expected Output: [[3.0, 2.0, 4.0], [3.5, 2.0, 4.0], [4.0, 4.0, 8.0]]
Explanation: Odd then even then odd counts. After 4 the count is even so median = (3+4)/2 = 3.5, still in [2,4]. After 5 the median is 4, which lands on the lower boundary of [4,8].
Input: ([1],)
Expected Output: [[1.0, 1.0, 2.0]]
Explanation: Single element: median 1 = 2^0, interval [1, 2].
Input: ([8],)
Expected Output: [[8.0, 8.0, 16.0]]
Explanation: Median is exactly the power of two 8 = 2^3, so it sits on the lower boundary: interval [8, 16].
Input: ([5, 5, 5, 5],)
Expected Output: [[5.0, 4.0, 8.0], [5.0, 4.0, 8.0], [5.0, 4.0, 8.0], [5.0, 4.0, 8.0]]
Explanation: All duplicates: median stays 5 at every step; 4 < 5 < 8 so the interval is always [4, 8].
Input: ([1000000],)
Expected Output: [[1000000.0, 524288.0, 1048576.0]]
Explanation: Large value: 2^19 = 524288 <= 1000000 < 1048576 = 2^20, so the interval is [524288, 1048576].
Input: ([7, 3, 1, 9, 5],)
Expected Output: [[7.0, 4.0, 8.0], [5.0, 4.0, 8.0], [3.0, 2.0, 4.0], [5.0, 4.0, 8.0], [5.0, 4.0, 8.0]]
Explanation: Unsorted stream. Running medians are 7, 5, 3, 5, 5; the heaps keep the running order correct so each median maps to the right power-of-two bucket.
Input: ([2, 6],)
Expected Output: [[2.0, 2.0, 4.0], [4.0, 4.0, 8.0]]
Explanation: After 2: median 2 = 2^1 on the lower boundary -> [2,4]. After 6: even count, median = (2+6)/2 = 4 = 2^2 on the lower boundary -> [4,8].
Hints
- Maintain two heaps: a max-heap for the lower half and a min-heap for the upper half. Keep their sizes balanced so the median is at the heap tops.
- For an even count the median is the average of the two heap tops and can be a non-integer such as 3.5; for an odd count it is the larger heap's top.
- The loose median k = floor(log2(median)). Compute the bounds as 1<<k and 1<<(k+1). Because log2 of a float can be slightly off near a power of two, verify and nudge k with a small while-loop so that 2^k <= median < 2^(k+1).
- When the median equals a power of two (e.g. 8), it sits on the lower boundary, giving [8, 16].