295. 数据流的中位数

import heapq
from typing import List

class MedianFinder:
    """
    使用双堆(一个最大堆,一个最小堆)来查找数据流的中位数。
    """

    def __init__(self):
        """
        初始化数据结构。
        使用两个堆:
        self.small_half: 最大堆,存储数据流中较小的一半数字。
                       (用最小堆 heapq 实现,存储元素的负数)
        self.large_half: 最小堆,存储数据流中较大的一半数字。
        约定:len(self.small_half) >= len(self.large_half),两者大小差不超过 1。
        """
        self.small_half = []  # 存储负数,模拟最大堆
        self.large_half = []  # 标准最小堆

    def addNum(self, num: int) -> None:
        """
        将整数 num 添加到数据流中。
        """
        
        # 1. 先将 num 的负数加入 small_half (模拟最大堆)
        #    这样 small_half 堆顶的负数是最小的,对应的原始数是最大的。
        heapq.heappush(self.small_half, -num)

        # 2. 维护数值属性:确保 small_half 的所有元素 <= large_half 的所有元素
        #    将 small_half 中最大的元素(即 -self.small_half[0])移动到 large_half
        largest_in_small = -heapq.heappop(self.small_half)
        heapq.heappush(self.large_half, largest_in_small)

        # 3. 维护大小属性:确保 len(small_half) >= len(large_half)
        #    如果 large_half 的大小超过了 small_half,则需要平衡
        if len(self.large_half) > len(self.small_half):
            # 将 large_half 中最小的元素移回 small_half
            smallest_in_large = heapq.heappop(self.large_half)
            heapq.heappush(self.small_half, -smallest_in_large) # 存入负数

    def findMedian(self) -> float:
        """
        返回当前数据流的中位数。
        """
        # 如果两个堆大小相等(总元素个数为偶数)
        if len(self.small_half) == len(self.large_half):
            # 中位数是两个堆顶元素的平均值
            # small_half 堆顶是 -self.small_half[0] (取反得到原始最大值)
            # large_half 堆顶是 self.large_half[0] (最小值)
            return (-self.small_half[0] + self.large_half[0]) / 2.0
        # 如果 small_half 比 large_half 多一个元素(总元素个数为奇数)
        else: 
            # 中位数是 small_half 的堆顶元素 (取反得到原始值)
            # 根据约定,此时 small_half 恰好多一个元素
            return -self.small_half[0] / 1.0 # 除以 1.0 确保结果是浮点数

    
    
    
    
    
    
    
    """
    使用双堆查找数据流中位数 (模拟 C++ 代码逻辑)。
    """

    def __init__(self):
        """
        初始化数据结构。
        self.small: 最大堆 (用 heapq 存负数模拟),存较小一半。
        self.large: 最小堆,存较大一半。
        允许大小差为 1。
        """
        self.small = []  # 模拟最大堆
        self.large = []  # 标准最小堆

    def addNum(self, num: int) -> None:
        """
        将整数 num 添加到数据流中 (遵循 C++ 代码逻辑)。
        """
        
        # 1. 直接将 num 的负数加入 small (模拟最大堆)
        heapq.heappush(self.small, -num)

        # 2. 条件性维护数值属性 (仅当 small 顶 > large 顶时移动)
        #    需要检查堆不为空
        if self.small and self.large and (-self.small[0] > self.large[0]):
            largest_in_small = -heapq.heappop(self.small)
            heapq.heappush(self.large, largest_in_small)

        # 3. 维护大小平衡 (允许差值为 1,用两个 if 判断)
        # 情况 a: small 比 large 多出超过 1 个
        if len(self.small) > len(self.large) + 1:
            largest_in_small = -heapq.heappop(self.small)
            heapq.heappush(self.large, largest_in_small)
            
        # 情况 b: large 比 small 多出超过 1 个
        # 注意:这两个 if 条件理论上不会同时满足,但这是 C++ 代码的结构
        if len(self.large) > len(self.small) + 1:
            smallest_in_large = heapq.heappop(self.large)
            heapq.heappush(self.small, -smallest_in_large)

    def findMedian(self) -> float:
        """
        返回当前数据流的中位数 (匹配 C++ 代码的逻辑)。
        """
        # 如果 large 比 small 多一个元素
        if len(self.large) > len(self.small):
            return self.large[0] / 1.0 # 最小堆堆顶
        # 如果 small 比 large 多一个元素
        elif len(self.small) > len(self.large):
             # 最大堆堆顶 (取反)
            return -self.small[0] / 1.0
        # 如果两个堆大小相等 (且都不为空)
        elif self.small and self.large:
             # 中位数是两个堆顶元素的平均值
            return (-self.small[0] + self.large[0]) / 2.0
        # 处理其中一个堆为空或初始状态 (根据题目约束可能不需要)
        elif self.small:
             return -self.small[0] / 1.0
        elif self.large:
             return self.large[0] / 1.0
        else:
             return 0.0 # 或者抛出异常,如果数据流为空






# 示例用法:
# medianFinder = MedianFinder()
# medianFinder.addNum(1)    # arr = [1]
# medianFinder.addNum(2)    # arr = [1, 2]
# print(medianFinder.findMedian()) # 输出: 1.5
# medianFinder.addNum(3)    # arr = [1, 2, 3]
# print(medianFinder.findMedian()) # 输出: 2.0 



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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值