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

例如,

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

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

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

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:

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

 

需要明确的是:大顶堆中的元素是小顶堆里最小值取负后再加入的,因此大顶堆中(忽略负号)的元素肯定比小顶堆中的小。然后,让小顶堆的长度总是大于或等于大顶堆。因此当长度为奇数时,中位数就是小顶堆的堆首,为偶数时就是(大顶堆堆首+小顶堆堆首)/2

import heapq
class MedianFinder(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.len = 0
        #小顶堆
        self.minheap = []
        #大顶堆
        self.maxheap = []

    def addNum(self, num):
        """
        :type num: int
        :rtype: None
        """
        #加入一个数,长度加1
        self.len += 1
        #首先明确的是python中的heapq是小顶堆
        #heappushpop:将num放入堆中,然后弹出并返回heap的最小元素。
        #heappush:将item的值加入heap中,保持堆的不变性。
        #heappop:弹出并返回heap的最小的元素,保持堆的不变性。
        heapq.heappush(self.maxheap, -heapq.heappushpop(self.minheap, num))
        if len(self.maxheap) > len(self.minheap):
            heapq.heappush(self.minheap, -heapq.heappop(self.maxheap))
        print("小顶堆:",self.minheap)
        print("大顶堆:",self.maxheap)

    def findMedian(self):
        """
        :rtype: float
        """
        if self.len & 1 == 0:
            return (self.minheap[0] - self.maxheap[0]) / 2.0
        return self.minheap[0]
        

m=MedianFinder()
m.addNum(4)
print("中位数:",m.findMedian())
m.addNum(1)
print("中位数:",m.findMedian())
m.addNum(5)
print("中位数:",m.findMedian())
m.addNum(2)
print("中位数:",m.findMedian())
m.addNum(7)
print("中位数:",m.findMedian())

过程:负号只是占位用。

【python-leetcode295-双堆】数据流的中位数_数据结构