【每日一题】12.Running Median (对顶堆)

补题链接:Here

题意:动态的维护中位数的问题,依次读入一个整数,每当总个数为奇数时输出此时序列的中位数

使用对顶堆的在线做法。

为了实时找到中位数,我们可以建议两个二叉堆:一个小根堆、一个大根堆。在依次读入数字的过程设当前序列长度为 M,我们始终保持:

  1. 序列中从小到大排名为 1 ~ M/2 的整数存储在大根堆中;
  2. 序列中从小到大排名为 M/2+1 ~ M 的整数存储在小根堆中。

任何时候如果某一个堆中元素过多则是打破了平衡需要取出该堆的堆顶插入到另一个堆。这样一来序列的中位数就是小根堆的堆顶

关于新数 X 插入:如果 X 比中位数小,则插入大根堆,否则就插入小根堆。之后再维护平衡即可

上述算法就是 “对顶堆” 算法

这个代码会爆空间,但很好的实现的上述过程

priority_queue<int> q1, q2;
void solve() {
    while (q1.size()) q1.pop();
    while (q2.size()) q2.pop();

    int num, n;
    cin >> num >> n;
    cout << num << " " << (n + 1) / 2 << "\n";
    int a;
    cin >> a;
    cout << a << " ";
    q2.push(-a);
    int cnt = 1;
    for (int i = 2; i <= n; ++i) {
        cin >> a;
        if (a < -q2.top()) q1.push(a);
        else
            q2.push(-a);
        int s = q1.size();
        if (s > i / 2) {
            q2.push(-q1.top());
            q1.pop();
        }
        if (s < i / 2) {
            q1.push(-q2.top());
            q2.pop();
        }
        if (i & 1) {
            cout << -q2.top() << " ";
            if (++cnt % 10 == 0) cout << endl;
        }
    }
    cout << "\n";
}

AC 代码

vector<short> a;
void solve() {
    a.clear();
    int k, n;
    cin >> k >> n;
    cout << k << " " << (n + 1) / 2 << "\n";
    for (int i = 1; i <= n; ++i) {
        short x;
        cin >> x;
        a.insert(upper_bound(a.begin(), a.end(), x), x);
        if (i & 1) cout << a[(i - 1) / 2] << " ";
        if (i % 20 == 0) cout << "\n";
    }
    cout << "\n";
}
posted @   RioTian  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
点击右上角即可分享
微信分享提示