Bird
Raised Fist0
Interview Prepchallenge-problemshardAmazonFacebookGoogleMicrosoft

Find Median from Data Stream

Choose your preparation mode4 modes available
📋
Problem

Imagine you are monitoring live sensor data or stock prices and need to report the median value at any moment as new data arrives continuously.

Design a data structure that supports adding numbers from a data stream and finding the median of all elements so far. Implement two methods: addNum(int num) - adds a number to the data structure; findMedian() - returns the median of all elements added so far. The median is the middle value in an ordered integer list. If the size of the list is even, the median is the average of the two middle numbers.

1 ≤ number of addNum calls ≤ 10^5-10^5 ≤ num ≤ 10^5At least one element will be present before calling findMedian
Edge cases: Only one element added → median is that elementAll elements are the same → median is that elementLarge number of elements with duplicates → median calculation remains correct
</>
IDE
class MedianFinder: def __init__(self): pass def addNum(self, num: int) -> None: pass def findMedian(self) -> float: passpublic class MedianFinder { public MedianFinder() {} public void addNum(int num) {} public double findMedian() { return 0; } }class MedianFinder { public: MedianFinder() {} void addNum(int num) {} double findMedian() { return 0; } };class MedianFinder { constructor() {} addNum(num) {} findMedian() { return 0; } }
class MedianFinder:
    def __init__(self):
        # Write your solution here
        pass
    def addNum(self, num: int) -> None:
        pass
    def findMedian(self) -> float:
        pass
public class MedianFinder {
    public MedianFinder() {
        // Write your solution here
    }
    public void addNum(int num) {
    }
    public double findMedian() {
        return 0;
    }
}
#include <vector>
using namespace std;

class MedianFinder {
public:
    MedianFinder() {
        // Write your solution here
    }
    void addNum(int num) {
    }
    double findMedian() {
        return 0;
    }
};
class MedianFinder {
    constructor() {
        // Write your solution here
    }
    addNum(num) {
    }
    findMedian() {
        return 0;
    }
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: Median values off by one or incorrect averagesNot balancing the two heaps properly after insertion✅ After each addNum, rebalance heaps so their sizes differ by at most one
Wrong: Median is always the last inserted element or first elementUsing a greedy approach that does not maintain order or balance✅ Use two heaps to maintain lower and upper halves and compute median from heap tops
Wrong: Median incorrect when duplicates are presentIgnoring duplicates or treating them as single elements✅ Insert all duplicates into heaps and balance normally
Wrong: TLE on large inputsSorting entire list on every addNum call✅ Implement two heaps approach for O(log n) insertion and O(1) median retrieval
Wrong: Median calculation causes integer overflow or wrong averagingUsing integer division or not using float/double for median✅ Use float/double type and compute average as (a + b) / 2.0
✓
Test Cases
t1_01basic
Input["addNum(1)","addNum(2)","findMedian()","addNum(3)","findMedian()"]
Expected[1.5,2]

After adding 1 and 2, the sorted list is [1,2], median is (1+2)/2=1.5. After adding 3, list is [1,2,3], median is 2.

t1_02basic
Input["addNum(5)","addNum(15)","addNum(1)","findMedian()","addNum(3)","findMedian()"]
Expected[5,4]

After adding 5,15,1 the sorted list is [1,5,15], median is 5. After adding 3, list is [1,3,5,15], median is (3+5)/2=4.

t2_01edge
Input["addNum(10)","findMedian()"]
Expected[10]

Only one element added, median is that element itself.

t2_02edge
Input["addNum(7)","addNum(7)","addNum(7)","findMedian()"]
Expected[7]

All elements are the same, median is that element.

t2_03edge
Input["addNum(-100000)","addNum(100000)","findMedian()"]
Expected[0]

Elements at boundary values, median is average of -100000 and 100000 = 0.

t3_01corner
Input["addNum(1)","addNum(2)","addNum(3)","addNum(4)","addNum(5)","findMedian()"]
Expected[3]

Sequential increasing numbers, median is middle element 3.

t3_02corner
Input["addNum(1)","addNum(1)","addNum(1)","addNum(1)","findMedian()"]
Expected[1]

Repeated identical elements, test for confusion between 0/1 knapsack style counting and median calculation.

t3_03corner
Input["addNum(100000)","addNum(-100000)","addNum(0)","addNum(99999)","addNum(-99999)","findMedian()"]
Expected[0]

Mixed large positive and negative numbers, median is 0 after sorting [-100000,-99999,0,99999,100000].

t4_01performance
Input["addNum(0)","addNum(1)","addNum(2)","addNum(3)","addNum(4)","addNum(5)","addNum(6)","addNum(7)","addNum(8)","addNum(9)","addNum(10)","addNum(11)","addNum(12)","addNum(13)","addNum(14)","addNum(15)","addNum(16)","addNum(17)","addNum(18)","addNum(19)","addNum(20)","addNum(21)","addNum(22)","addNum(23)","addNum(24)","addNum(25)","addNum(26)","addNum(27)","addNum(28)","addNum(29)","addNum(30)","addNum(31)","addNum(32)","addNum(33)","addNum(34)","addNum(35)","addNum(36)","addNum(37)","addNum(38)","addNum(39)","addNum(40)","addNum(41)","addNum(42)","addNum(43)","addNum(44)","addNum(45)","addNum(46)","addNum(47)","addNum(48)","addNum(49)","addNum(50)","addNum(51)","addNum(52)","addNum(53)","addNum(54)","addNum(55)","addNum(56)","addNum(57)","addNum(58)","addNum(59)","addNum(60)","addNum(61)","addNum(62)","addNum(63)","addNum(64)","addNum(65)","addNum(66)","addNum(67)","addNum(68)","addNum(69)","addNum(70)","addNum(71)","addNum(72)","addNum(73)","addNum(74)","addNum(75)","addNum(76)","addNum(77)","addNum(78)","addNum(79)","addNum(80)","addNum(81)","addNum(82)","addNum(83)","addNum(84)","addNum(85)","addNum(86)","addNum(87)","addNum(88)","addNum(89)","addNum(90)","addNum(91)","addNum(92)","addNum(93)","addNum(94)","addNum(95)","addNum(96)","addNum(97)","addNum(98)","addNum(99)","findMedian()"]
⏱ Performance - must finish in 2000ms

n=100 addNum calls followed by findMedian; O(log n) per addNum and O(1) findMedian must complete within 2 seconds.

Practice

(1/5)
1. Given the following Python code snippet implementing the optimized trie approach, what is the output of maximizeXor(nums, queries) for nums = [0,1,2] and queries = [[3,1],[1,2]]?
class TrieNode:
    def __init__(self):
        self.children = [null, null]

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, num):
        node = self.root
        for i in range(31, -1, -1):
            bit = (num >> i) & 1
            if not node.children[bit]:
                node.children[bit] = TrieNode()
            node = node.children[bit]

    def maxXor(self, num):
        node = self.root
        if not node.children[0] and not node.children[1]:
            return -1
        max_xor = 0
        for i in range(31, -1, -1):
            bit = (num >> i) & 1
            toggled_bit = 1 - bit
            if node.children[toggled_bit]:
                max_xor |= (1 << i)
                node = node.children[toggled_bit]
            else:
                node = node.children[bit]
        return max_xor

def maximizeXor(nums, queries):
    nums.sort()
    queries = sorted([(x, m, i) for i, (x, m) in enumerate(queries)], key=lambda x: x[1])
    res = [-1] * len(queries)
    trie = Trie()
    idx = 0
    n = len(nums)
    for x, m, i in queries:
        while idx < n and nums[idx] <= m:
            trie.insert(nums[idx])
            idx += 1
        res[i] = trie.maxXor(x)
    return res

print(maximizeXor(nums, queries))
easy
A. [3, 3]
B. [2, 3]
C. [3, 1]
D. [-1, 3]

Solution

  1. Step 1: Process first query (3,1)

    Only nums ≤ 1 are [0,1]. Insert 0 and 1 into trie. maxXor(3) with {0,1} is max(3^0=3,3^1=2)=3.
  2. Step 2: Process second query (1,2)

    Now nums ≤ 2 are [0,1,2]. Insert 2. maxXor(1) with {0,1,2} is max(1^0=1,1^1=0,1^2=3)=3.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Results match expected XOR values [OK]
Hint: Insert nums ≤ m incrementally, then maxXor query [OK]
Common Mistakes:
  • Forgetting to sort queries and nums
  • Not inserting all eligible nums before query
  • Returning -1 when trie is empty incorrectly
2. You are given a list of buildings represented as triplets (left, right, height). The goal is to output the skyline formed by these buildings as a list of key points where the height changes. Which algorithmic approach guarantees an optimal solution with time complexity O(n log n) for this problem?
easy
A. Divide and conquer approach that recursively merges skylines of building subsets
B. Greedy approach that iteratively picks the tallest building at each x-coordinate
C. Dynamic programming approach that stores maximum heights for subproblems
D. Brute force simulation by mapping heights on a large array and scanning

Solution

  1. Step 1: Understand problem constraints

    The problem requires merging multiple building outlines efficiently, which suggests a divide and conquer strategy to combine partial skylines.
  2. Step 2: Compare approaches

    Greedy and brute force approaches are either incorrect or inefficient (O(n * maxRight)). Dynamic programming does not naturally fit this problem. Divide and conquer achieves O(n log n) by recursively merging skylines.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Divide and conquer merges partial results efficiently [OK]
Hint: Divide and conquer merges partial skylines efficiently [OK]
Common Mistakes:
  • Believing greedy approach works optimally
  • Thinking DP applies naturally here
  • Assuming brute force is efficient enough
3. Examine the following modified code snippet for the Alien Dictionary problem. Which line contains a subtle bug that can cause incorrect results on certain inputs?
medium
A. Line incrementing in_degree[w2[j]] after adding edge
B. Missing prefix invalid case check after min_len calculation
C. Line checking if w2[j] not in graph[w1[j]] before adding edge
D. Line initializing queue with characters having zero in-degree

Solution

  1. Step 1: Identify missing prefix invalid case check

    Code lacks check for case where longer word precedes its prefix (e.g., "abc" before "ab"), which is invalid.
  2. Step 2: Understand consequences of missing this check

    Without this, function may return incorrect order or fail to detect invalid input.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Prefix invalid case is critical for correctness [OK]
Hint: Look for missing validation of prefix ordering [OK]
Common Mistakes:
  • Ignoring prefix invalid case
  • Adding duplicate edges
  • Incorrect in-degree updates
4. Suppose the histogram bars can be reused multiple times to form rectangles (i.e., you can select the same bar multiple times consecutively). Which modification to the single pass stack-based algorithm correctly handles this variant?
hard
A. Use the same stack-based approach but remove the sentinel bar
B. Switch to a dynamic programming approach that counts repeated bars explicitly
C. Modify width calculation to include repeated bars by removing '-1' in width formula
D. No modification needed; the original algorithm already handles reuse

Solution

  1. Step 1: Understand reuse implication

    Allowing reuse means rectangles can extend beyond contiguous bars, breaking the assumption that each bar is used once in a contiguous segment.
  2. Step 2: Why stack approach fails

    The stack-based method relies on contiguous bars and their indices; it cannot track multiple uses of the same bar or non-contiguous reuse.
  3. Step 3: Correct approach

    A dynamic programming approach that explicitly counts repeated bars or uses a different state representation is needed to handle reuse correctly.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Stack method assumes single use; DP needed for reuse [OK]
Hint: Reuse breaks contiguous assumption; DP needed [OK]
Common Mistakes:
  • Thinking original stack method handles reuse
  • Trying to fix width formula only
  • Removing sentinel bar to fix reuse
5. Suppose the problem is modified so that words can be reused multiple times in pairs (i.e., pairs (i, j) where i == j are allowed). Which modification to the Trie-based solution correctly handles this variant without double counting pairs?
hard
A. Remove the check 'node.index != index' and filter duplicates from final results
B. Keep the check 'node.index != index' but add a separate check for empty string pairs
C. Modify add_word to store multiple indices per node to allow reuse tracking
D. Remove the check 'node.index != index' in search to allow i == j pairs

Solution

  1. Step 1: Understand reuse allowance

    Allowing i == j pairs means removing the 'node.index != index' check to include self-pairs.
  2. Step 2: Avoid double counting

    Removing the check causes duplicates; filtering duplicates after collecting results ensures correctness.
  3. Step 3: Evaluate other options

    Keeping the check disallows self-pairs; storing multiple indices per node is unnecessary and complex.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Removing check plus duplicate filtering correctly handles reuse [OK]
Hint: Allow self-pairs by removing check, then deduplicate results [OK]
Common Mistakes:
  • Removing check without deduplication
  • Keeping check and missing self-pairs
  • Overcomplicating Trie nodes
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard