1.题目
![](https://i-blog.csdnimg.cn/blog_migrate/1a5453155812f4b3d41528d54709f119.png)
2.适用范围
一般适用于求多组数的中位数
根据题目要求,中位数是down.top()或者是(up.top() + down.top()) / 2
其它细节都在代码注释里
3.数据结构模型
4.代码如下
class DualHeap {
private:
// 下堆是大根堆
priority_queue<int> down;
// 上堆是小根堆
priority_queue<int, vector<int>, greater<int>> up;
// 延迟删除堆中元素,只有当其在堆顶的时候才进行删除
// [k, v] 分别代表[要删除的数值、出现的次数]
unordered_map<int, int> delayed;
// 窗口大小(题目要求)
int k;
// 这里十分重要,调整平衡的时候不是比较虚拟大小(down.size),而是比较真实大小
// 记录上下堆的实际大小
int downSize, upSize;
public:
DualHeap(int _k): k(_k), downSize(0), upSize(0) {}
private:
// 延迟删除(修剪)
// 如果堆顶元素是要删除的元素,则一直删除,直到堆顶元素在滑窗内
void prune(auto &heap) {
while (heap.size()) {
int x = heap.top();
if (delayed.count(x)) {
if (-- delayed[x] == 0)
delayed.erase(x);
heap.pop();
}
else break;
}
}
// 维持两个堆的大小
/** 维持条件:
1.下堆至多大于上堆1个,至少与上堆个数相等
2.min(上堆) >= max(下堆)
**/
void makeBalance() {
if (downSize > upSize + 1) {s
up.push(down.top());
down.pop();
-- downSize, ++ upSize;
prune(down);
}
else if (downSize < upSize) {
down.push(up.top());
up.pop();
++ downSize, -- upSize;
prune(up);
}
}
public:
// 插入
void insert(int num) {
if (down.empty() || num <= down.top()) down.push(num), ++ downSize;
else up.push(num), ++ upSize;
makeBalance();
}
// 删除
void erase(int num) {
++ delayed[num];
if (num <= down.top()) {
-- downSize;
if (num == down.top())
prune(down);
}
else {
-- upSize;
if (num == up.top())
prune(up);
}
makeBalance();
}
// 求中位数(题目要求)
double getMedian() {
return k & 1 ? down.top() : ((double)down.top() + up.top()) / 2;
}
};
5.相似题型
https://www.acwing.com/activity/content/problem/content/1793/