We can find the median from a data stream by always keeping a sorted list of all the items so far. We then can always find the median quickly ( time).

The two heaps approach is better though time complexity wise. It’s to find medians, unlike this sorted list which is . Insertion is the same for both though.

from sortedcontainers import SortedList
 
class MedianFinder:
    def __init__(self):
        self.nums = SortedList()
        self.len = 0
 
    def addNum(self, num: int) -> None:
        self.nums.add(num)
        self.len += 1
 
    def findMedian(self) -> float:
        if self.len % 2:
            return self.nums[self.len // 2]
        else:
            left = self.nums[self.len // 2 - 1]
            right = self.nums[self.len // 2]
            return (left + right) / 2
import heapq
 
class MedianFinder:
    def __init__(self):
        self.small = []  # max-heap (store negative numbers)
        self.large = []  # min-heap
 
    def addNum(self, num: int) -> None:
        # Push to small (max-heap)
        heapq.heappush(self.small, -num)
 
        # Ensure every element in small <= every element in large
        if self.small and self.large and -self.small[0] > self.large[0]:
            val = -heapq.heappop(self.small)
            heapq.heappush(self.large, val)
 
        # Balance sizes (small can have at most 1 more element than large)
        if len(self.small) > len(self.large) + 1:
            heapq.heappush(self.large, -heapq.heappop(self.small))
        if len(self.large) > len(self.small):
            heapq.heappush(self.small, -heapq.heappop(self.large))
 
    def findMedian(self) -> float:
        if len(self.small) > len(self.large):
            return -self.small[0]
        return (-self.small[0] + self.large[0]) / 2