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()
295. 数据流的中位数
最新推荐文章于 2025-06-26 09:15:57 发布