What if you could instantly know the middle value of a never-ending list without sorting it every time?
Why Median of Data Stream Using Two Heaps in DSA Python?
Imagine you are tracking the middle value of a growing list of numbers, like daily temperatures or scores, but you get the numbers one by one and want to know the middle value at any time.
Manually sorting the list every time a new number arrives is slow and tiring. It takes longer as the list grows, and you might make mistakes finding the middle value quickly.
Using two heaps (one for smaller half, one for larger half) keeps the numbers balanced. This way, you can quickly find the middle value without sorting the whole list each time.
numbers = [] numbers.append(new_number) numbers.sort() median = numbers[len(numbers)//2]
small_half = MaxHeap() large_half = MinHeap() add_number(new_number) median = get_median()
This method lets you find the middle value instantly as new numbers come in, even if the list is very long.
Streaming apps showing live median user ratings or sensor data that updates constantly and needs quick middle value calculations.
Manual sorting every time is slow and error-prone.
Two heaps keep data balanced for fast median access.
Efficient for continuous data streams and real-time updates.
Practice
Solution
Step 1: Understand the role of two heaps
The max heap stores the smaller half of the numbers, and the min heap stores the larger half.Step 2: Explain median calculation
By balancing these heaps, the median can be found quickly from the top elements of the heaps.Final Answer:
To efficiently keep track of the lower half and upper half of the numbers for median calculation -> Option AQuick Check:
Two heaps split data halves = efficient median [OK]
- Thinking heaps sort all data fully
- Using one heap only
- Confusing heaps with arrays
Solution
Step 1: Understand heap initialization in Python
Python's heapq module only supports min heaps, so to simulate a max heap, we store negative values in a list.Step 2: Check code correctness
max_heap = [] # will store negative values for max heap behavior min_heap = [] correctly initializes empty lists for both heaps; max heap will store negative values to simulate max heap behavior.Final Answer:
max_heap = [] # will store negative values for max heap behavior min_heap = [] -> Option CQuick Check:
Empty lists + negative values = max heap simulation [OK]
- Calling heapq.heapify on empty list returns None
- Trying to create max heap directly
- Confusing heapq.heapify return value
import heapq
class MedianFinder:
def __init__(self):
self.max_heap = []
self.min_heap = []
def add_num(self, num):
if not self.max_heap or num <= -self.max_heap[0]:
heapq.heappush(self.max_heap, -num)
else:
heapq.heappush(self.min_heap, num)
if len(self.max_heap) > len(self.min_heap) + 1:
heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap))
elif len(self.min_heap) > len(self.max_heap):
heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))
def get_median(self):
if len(self.max_heap) > len(self.min_heap):
return float(-self.max_heap[0])
else:
return (-self.max_heap[0] + self.min_heap[0]) / 2
finder = MedianFinder()
for number in [5, 15, 1, 3]:
finder.add_num(number)
print(finder.get_median())Solution
Step 1: Insert numbers and balance heaps
Insert 5: max_heap=[-5], min_heap=[]; median=5 Insert 15: max_heap=[-5], min_heap=[15]; median=(5+15)/2=10 Insert 1: max_heap=[-5,-1], min_heap=[15]; median=5 Insert 3: max_heap=[-3,-1], min_heap=[5,15]; median=(3+5)/2=4.0Step 2: Calculate final median
After all insertions, median is 4.0 as heaps are balanced and median is average of tops.Final Answer:
4.0 -> Option DQuick Check:
Median after 4 inserts = 4.0 [OK]
- Not balancing heaps after insertion
- Forgetting to invert max heap values
- Calculating median incorrectly for even count
def add_num(self, num):
if not self.max_heap or num < -self.max_heap[0]:
heapq.heappush(self.max_heap, -num)
else:
heapq.heappush(self.min_heap, num)
if len(self.max_heap) > len(self.min_heap):
heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap))
elif len(self.min_heap) > len(self.max_heap) + 1:
heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))Solution
Step 1: Analyze balancing conditions
The code moves elements when max_heap size > min_heap size, but it should allow max_heap to be larger by at most 1.Step 2: Identify correct balancing logic
Correct logic: if max_heap size > min_heap size + 1, move element to min_heap; if min_heap size > max_heap size, move element to max_heap.Final Answer:
The balancing conditions are reversed; max_heap can grow too large -> Option AQuick Check:
Balance heaps with correct size difference [OK]
- Swapping balancing conditions
- Not allowing max_heap to be bigger by one
- Incorrect comparison operators
Solution
Step 1: Understand removal challenges with heaps
Heaps do not support efficient arbitrary removal; rebuilding heaps after each removal is costly.Step 2: Identify suitable data structure
Balanced binary search trees support insertion, removal, and median retrieval in O(log n) time.Step 3: Compare other options
Sorted lists have O(n) removal; hash maps do not maintain order; rebuilding heaps is inefficient.Final Answer:
Use balanced binary search trees (like AVL or Red-Black trees) instead of heaps -> Option BQuick Check:
Balanced BSTs support fast insert/remove/median [OK]
- Assuming heaps support fast removal
- Using sorted lists with slow removal
- Ignoring order maintenance
Ready to prove it?
Pass the test and this pattern moves unknown
