python中的大小堆 heapq
首先看例子:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof
解:
from heapq import * class MedianFinder: def __init__(self): # 大小堆一半一半,中位数只要取堆顶 但是python中的堆 堆的索引位置0的值是堆中的最小值 【B | A】 """ 建立一个 小顶堆 A 和 大顶堆 B ,各保存列表的一半元素,且规定: A 保存 较大 的一半,长度为 \frac{N}{2}( N 为偶数)或 \frac{N+1}{2} ( N 为奇数); B 保存 较小 的一半,长度为 \frac{N}{2}( N 为偶数)或 \frac{N-1}{2} ( N 为奇数); 随后,中位数可仅根据 A, B的堆顶元素计算得到。 """ self.A = [] #小顶堆 堆顶为最小值 self.B = [] #大顶堆 堆顶为最大值(所以实现起来 用 负数) def addNum(self, num: int) -> None: if len(self.A)!=len(self.B): heappush(self.A,num) heappush(self.B,-heappop(self.A)) else: heappush(self.B,-num) heappush(self.A,-heappop(self.B)) def findMedian(self) -> float: return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0
heap
文档:heapq --- 堆队列算法 — Python 3.10.0 文档
- 只能是列表
- 能通过"<"比较
- 堆特性
一个列表heap它里面的每一个元素都符合 heap[0] <= heap[2*k+1]和heap[0] <= heap[2*k+2] ,那么这个heap就具有堆特性(python中的堆是最小堆, 也就是说堆的索引位置0的值是堆中的最小值.)
heapq.heappop(heap) 弹出索引位置0中的值
大佬:heapq.heappop(heap) 弹出索引位置0中的值 - 跟丫死磕 (weshallneversurrender.com)
heapq.heappush() 将一个对象压入堆中
大佬:python heapq.heappush() 将一个对象压入堆中 - 跟丫死磕 (weshallneversurrender.com)
C++中的大小堆用法解题
用库函数 priority_queue<int,vector<int>,less<int>> or priority_queue<int,vector<int>,greater<int>> 方便地实现大小堆:Priority Queue in C++ Standard Template Library (STL) - GeeksforGeeks
方法:
- res = minHeap.pop()
- minHeap.top()
- minHeap.push(item)
class MedianFinder { public: // 【左边 | 右边】 // 最大堆 堆顶为最大值 存储左边一半 priority_queue<int,vector<int>,less<int>> maxHeap; // 最小堆 堆顶为最小值 存储右边一半 priority_queue<int,vector<int>,greater<int>> minHeap; MedianFinder() { } void addNum(int num) { if(maxHeap.size()!=minHeap.size()){ maxHeap.push(num); int top_of_maxHeap = maxHeap.top(); maxHeap.pop(); minHeap.push(top_of_maxHeap); }else{ minHeap.push(num); int top_of_minHeap = minHeap.top(); minHeap.pop(); maxHeap.push(top_of_minHeap); } } double findMedian() { if(maxHeap.size()!=minHeap.size()){ return maxHeap.top()*1.0; }else{ return (maxHeap.top()+minHeap.top())*1.0/2; } } };
前 K 个高频元素
347. 前 K 个高频元素 - 力扣(LeetCode) (leetcode-cn.com)
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
- 可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 $O(n \log n)$ , n 是数组的大小。
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
用字典不就完事了吗?统计完还要排序的,排序用快排?
首先想到的就是map
map可以实现统计功能,但是对频数进行排序还是挺麻烦的,有没有可能我统计完,排序也出来了?有 ------容器适配器:优先级队列
可以理解为披着队列外衣的堆,常说的大小堆就是优先级队列
如果懒得自己实现的话,就直接用priority_queue(优先级队列)就可以了,底层实现都是一样的,从小到大排就是小顶堆,从大到小排就是大顶堆。
python中的大小堆 heapq - PiaYie - 博客园 (cnblogs.com)
大顶堆:每次弹出最大的元素
小顶堆:每次弹出最小的元素
思路:使用小顶堆存频数。当堆中数据多与k组时,每次把频数最小的数据弹出,最后返回的k个数据就是前 K 个高频元素
// 时间复杂度:O(nlogk) // 空间复杂度:O(n) class Solution { public: // 小顶堆 class mycomparison { public: bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) { return lhs.second > rhs.second; } }; vector<int> topKFrequent(vector<int>& nums, int k) { // 要统计元素出现频率 unordered_map<int, int> map; // map<nums[i],对应出现的次数> for (int i = 0; i < nums.size(); i++) { map[nums[i]]++; } // 对频率排序 // 定义一个小顶堆,大小为k priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que; // 用固定大小为k的小顶堆,扫面所有频率的数值 for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) { pri_que.push(*it); if (pri_que.size() > k) { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k pri_que.pop(); } } // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组 vector<int> result(k); for (int i = k - 1; i >= 0; i--) { result[i] = pri_que.top().first; pri_que.pop(); } return result; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~