news 2026/7/11 21:13:43

对顶堆实战:5分钟掌握动态中位数计算的Python实现(附LeetCode例题)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
对顶堆实战:5分钟掌握动态中位数计算的Python实现(附LeetCode例题)

对顶堆实战:5分钟掌握动态中位数计算的Python实现(附LeetCode例题)

在算法面试和竞赛中,动态中位数问题是一个经典的高频考点。想象这样一个场景:数据流不断涌入,你需要实时维护并快速返回当前所有数字的中位数。传统做法每次查询都重新排序显然效率太低,而对顶堆(Dual Heap)结构能以O(logN)时间复杂度优雅解决这个问题。本文将用Python带你从零实现这一数据结构,并解决LeetCode 295. Find Median from Data Stream等实际问题。

1. 什么是对顶堆?

对顶堆由两个堆组成:一个大根堆保存较小的一半数字,一个小根堆保存较大的一半数字。这种结构始终保持两个特性:

  1. 大根堆的所有元素 ≤ 小根堆的所有元素
  2. 两个堆的大小差不超过1

当满足这两个条件时,中位数计算就变得非常简单:

  • 如果总数是奇数:元素较多的堆顶即为中位数
  • 如果总数是偶数:两个堆顶的平均值即为中位数
import heapq class MedianFinder: def __init__(self): self.max_heap = [] # 保存较小的一半(Python默认小根堆,通过存储负数模拟大根堆) self.min_heap = [] # 保存较大的一半

2. Python实现核心操作

2.1 添加元素

每次新元素插入时需要决定放入哪个堆,并动态平衡两个堆的大小:

def addNum(self, num: int) -> None: if not self.max_heap or num <= -self.max_heap[0]: heapq.heappush(self.max_heap, -num) # 大根堆插入 else: heapq.heappush(self.min_heap, num) # 小根堆插入 # 平衡两个堆的大小 if len(self.max_heap) > len(self.min_heap) + 1: heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap)) elif len(self.min_heap) > len(self.max_heap): heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))

注意:Python的heapq模块只实现小根堆,我们通过存储负数来模拟大根堆行为

2.2 查询中位数

根据堆的大小关系返回相应结果:

def findMedian(self) -> float: if len(self.max_heap) == len(self.min_heap): return (-self.max_heap[0] + self.min_heap[0]) / 2 else: return -self.max_heap[0]

3. LeetCode 295完整解法

将上述代码组合起来就是完整的解决方案:

import heapq class MedianFinder: def __init__(self): self.max_heap = [] # 较小的一半 self.min_heap = [] # 较大的一半 def addNum(self, num: int) -> None: if not self.max_heap or num <= -self.max_heap[0]: heapq.heappush(self.max_heap, -num) else: heapq.heappush(self.min_heap, num) # Balance heaps if len(self.max_heap) > len(self.min_heap) + 1: heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap)) elif len(self.min_heap) > len(self.max_heap): heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap)) def findMedian(self) -> float: if len(self.max_heap) == len(self.min_heap): return (-self.max_heap[0] + self.min_heap[0]) / 2 else: return -self.max_heap[0]

时间复杂度分析:

  • 添加操作:O(logN)
  • 查询操作:O(1)

4. 常见错误与调试技巧

4.1 堆平衡不及时

初学者常犯的错误是在插入元素后忘记检查堆的大小平衡。这会导致中位数计算错误:

# 错误示例:忘记平衡堆 def addNum(self, num: int) -> None: if num <= -self.max_heap[0]: heapq.heappush(self.max_heap, -num) else: heapq.heappush(self.min_heap, num) # 缺少平衡代码!

4.2 边界条件处理

当堆为空时的特殊处理:

# 正确处理空堆情况 def addNum(self, num: int) -> None: if not self.max_heap or num <= -self.max_heap[0]: # 检查max_heap是否为空 heapq.heappush(self.max_heap, -num)

4.3 测试用例验证

建议用以下测试案例验证你的实现:

操作序列预期中位数
add(1)1
add(2)1.5
add(3)2
add(4)2.5
add(5)3

5. 性能优化与变种问题

5.1 延迟删除技巧

在某些场景下需要支持删除操作,可以采用"延迟删除"策略:

  • 维护一个哈希表记录待删除元素
  • 当元素出现在堆顶时才真正删除
  • 空间换时间,保持O(logN)时间复杂度

5.2 滑动窗口中位数

LeetCode 480. Sliding Window Median是对顶堆的进阶应用。解决方案:

  1. 维护一个大小固定的对顶堆
  2. 窗口滑动时删除离开的元素,添加新元素
  3. 使用延迟删除处理非堆顶元素
def medianSlidingWindow(nums: List[int], k: int) -> List[float]: pass # 实现留给读者练习

5.3 多语言实现对比

不同语言的对顶堆实现差异:

语言最大堆实现方式典型代码示例
Python使用负数模拟heapq.heappush(max_heap, -num)
JavaPriorityQueue+比较器new PriorityQueue<>(Collections.reverseOrder())
C++priority_queue默认大堆priority_queue<int> max_heap;

掌握对顶堆不仅能够解决动态中位数问题,它的思想还可以扩展到:

  • 实时统计系统的百分位数
  • 股票市场中间价计算
  • 游戏中的动态难度调整
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/23 13:25:28

Chandra OCR效果展示:PDF表单域识别+填写内容提取+结构化输出

Chandra OCR效果展示&#xff1a;PDF表单域识别填写内容提取结构化输出 1. 开篇&#xff1a;重新定义PDF表单处理体验 你是否曾经面对一堆填好的PDF表单头疼不已&#xff1f;手动录入表单数据既耗时又容易出错&#xff0c;特别是当表单数量多、字段复杂时&#xff0c;简直是一…

作者头像 李华
网站建设 2026/3/23 13:24:39

all-MiniLM-L6-v2效果实测:与BERT嵌入模型性能对比报告

all-MiniLM-L6-v2效果实测&#xff1a;与BERT嵌入模型性能对比报告 1. 模型介绍与测试背景 all-MiniLM-L6-v2是一个专门为高效语义表示设计的轻量级句子嵌入模型。这个模型基于BERT架构&#xff0c;但做了大量优化&#xff0c;让它在保持高性能的同时大幅减小了体积。 这个模…

作者头像 李华
网站建设 2026/3/23 13:21:30

芯片-设计流程入门

芯片近些年来一直是风口&#xff0c;几乎所有有实力的上市公司都要蹭下这个热度&#xff1a;自研芯片。这也诞生了很多工作岗位&#xff0c;相对于硬件工程师&#xff0c;软件开发工程师能做的事情有限&#xff0c;但是也是非常重要的&#xff0c;而且跟着风口喝口汤也是可以的…

作者头像 李华
网站建设 2026/3/23 13:21:29

NVIDIA ADAS-英伟达DriveOS入门

之前的文章汽车操作系统-现状及演进中&#xff0c;介绍过汽车中需要3种OS&#xff1a;智能座舱、智能驾驶、车控。 其中智能驾驶一直都是当今智能汽车最重要的一个竞争领域&#xff0c;也是智能车愿景的开端&#xff1a;无人驾驶。车控属于成熟****汽车电子系统的代表&#xf…

作者头像 李华
网站建设 2026/3/23 13:12:27

Llama-3.2V-11B-cot 本地化部署教程:使用Ollama简化模型管理与运行

Llama-3.2V-11B-cot 本地化部署教程&#xff1a;使用Ollama简化模型管理与运行 想在自己电脑上跑一个能看懂图片、还能跟你聊天的AI模型&#xff0c;但又觉得下载、配置、管理这些大文件太麻烦&#xff1f;今天就来聊聊怎么用Ollama这个“模型管家”&#xff0c;轻松把Llama-3…

作者头像 李华
网站建设 2026/3/23 13:12:27

恶意SQL无处遁形 | KingbaseES内置防火墙,主动防御更省心

在数字化转型的浪潮中&#xff0c;数据已成为企业的核心资产。然而&#xff0c;SQL注入攻击如同潜伏在阴影中的“不速之客”&#xff0c;时刻威胁着数据库的安全。即使开发团队严守预编译、输入过滤等防线&#xff0c;遗留代码、第三方组件的漏洞或人为疏忽仍可能给攻击者可乘之…

作者头像 李华