LeetCodeDiary

A Diary for solving LeetCode problems

View on GitHub

295. 数据流的中位数

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

进阶:

  1. 如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
  2. 如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

设计 堆 困难

代码

1. 最大最小堆

class MedianFinder:
    def __init__(self):
        self.max_h = []
        self.min_h = []
        heapify(self.max_h)
        heapify(self.min_h)
        
    def addNum(self, num):
       # 每次都插入到最小堆,然后,将最小堆里面的栈顶元素,
       # 取出来,放到最大堆中去,这样就能保证最小堆的堆,都比最大堆的堆顶大
       #(因为最大堆是最小堆,一泡屎一趴尿,拉扯大的。)
       # 下面的调整,使得最小最大堆元素相差最多为1,而且永远是 最小堆元素个数大于  等于最大堆元素个数
        heappush(self.min_h,num)
        heappush(self.max_h,-heappop(self.min_h))
        if len(self.min_h) < len(self.max_h):
            heappush(self.min_h,-heappop(self.max_h))
            
    def findMedian(self):
        max_len = len(self.max_h)
        min_len = len(self.min_h)
        return self.min_h[0]*1. if max_len!=min_len else (-self.max_h[0]+self.min_h[0])/2.



# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()

2. 维护有序数列

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.nums = []
        self.n = 0


    def addNum(self, num: int) -> None:
        bisect.insort(self.nums, num)
        self.n += 1

    def findMedian(self) -> float:
        mid = self.n // 2
        return self.nums[mid] if self.n % 2 else (self.nums[mid] + self.nums[mid-1])/2



# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()