LC 295堆与优先队列困难第 57 / 95 题

数据流的中位数

Find Median from Data Stream

双堆设计
本机进度仅保存在当前浏览器

题目描述

中位数是有序整数列表中的中间值。实现 MedianFinder 类:addNum(num) 从数据流中添加一个整数;findMedian() 返回目前所有元素的中位数。两方法都要求尽量高效。

示例:依次 addNum(1)、addNum(2),findMedian() 返回 1.5;addNum(3) 后 findMedian() 返回 2。

解题思路

  1. 双堆结构:大顶堆 small 存较小的一半,小顶堆 large 存较大的一半,两堆大小差不超过 1。
  2. 中位数:两堆等大时取堆顶平均;不等时取较大堆的堆顶。
  3. 插入规则:新数先进 large,再把 large 堆顶移到 small 保持有序划分;按两堆大小交替平衡。每次 O(log n)。
  4. 查询 O(1)——双堆把"动态有序集合取中位数"的成本压到了插入侧。

参考实现

查看参考实现Python · 建议先自行作答
import heapq

class MedianFinder:
    def __init__(self):
        self.small = []  # 大顶堆(存负值)
        self.large = []  # 小顶堆

    def addNum(self, num):
        # 先进 large,再搬运堆顶保持划分有序
        heapq.heappush(self.large, num)
        heapq.heappush(self.small, -heapq.heappop(self.large))
        # 平衡两堆大小:small 允许多一个
        if len(self.small) > len(self.large):
            heapq.heappush(self.large, -heapq.heappop(self.small))

    def findMedian(self):
        if len(self.large) > len(self.small):
            return float(self.large[0])
        return (self.large[0] - self.small[0]) / 2

复杂度与归属

时间复杂度O(log n) 插入 / O(1) 查询
空间复杂度O(n)
所属分类堆与优先队列
题源LeetCode 295

关联教程

返回题图鉴