求解第K大元素,第K小元素/前k大元素,前k小元素/中位数 (堆·二叉堆) poj1442/black box

如何求解一个第k大元素or第k小元素问题呢?/前k大元素or前k小元素

这类问题通常会有两种情况,1· 有序数组求解第k大, 2·无序数组(前k小or前k大)

通常对于第k大元素问题求解过程如下:
1·我们只需要用一个小顶堆
2·从数组中选择k个元素,加入堆中…按顺序加入即可,最小的元素一定是堆顶元素.
3·数组中剩下的元素依次与堆顶比较.(我们需维护小顶堆)
4·堆顶元素就是第k大堆元素

举例 1 2 3 4 5 求解第3大元素,我们只需要维护 有3个元素堆小顶堆.我们直观的看 第三大的就是3.
一开始将 1 2 3 加入堆中,1在堆顶.
第一轮 1 与 4 比较,大于堆顶元素则1出堆,4入堆 此时 堆顶为2
第二轮 2 与 5比较 同上 堆顶被调整为3
3便是我们需要的答案

第k小元素反之亦然,换成大顶堆

前k大元素 or 前k小元素

如果我们单一的用一个大顶堆或者一个小顶堆,难以解决这类问题
我们可以将这类问题 抽象成 求一个数组里的中位数问题
假设给一个数组 在此借用POJ1442 的Black Box 题目
在这里插入图片描述
在这里插入图片描述
大概解释一下,输入了n个数,m次询问.m次询问就是让我们求前m个元素中,第m小的元素

如果只用一个堆,是没有办法做解决的

所以我们需要使用二叉堆(对顶堆)

所有小堆元素 > 大堆元素,即可在大堆的堆顶找到第m小的元素

#include <iostream> 
using namespace std;
#include <set>
#define MAX 30000
int val[MAX+5] ={0};
typedef pair <int ,int> PII;
set<PII> s1,s2;
int main() {
    int n;
    int m;
    cin >> n>> m;
    for(int i = 1; i <= n; i++){
        cin >> val[i];
    }
    for(int i = 1, j = 0; i <= m; i++) {
        int k;
        cin >> k;
        while ( j < k ) {
            ++j;
            if(s1.size() == 0 || -s1.begin()->first > val[j]){ //
                s1.insert(PII(-val[j],j));
            }else {
                s2.insert(PII(val[j],j));
            }
        }
        while (s1.size() > i) {
            s2.insert(PII(-s1.begin()->first , s1.begin()->second));
            s1.erase(s1.begin());
        }
        while (s1.size() < i) {
            s1.insert(PII(-s2.begin()->first , s2.begin()->second));
            s2.erase(s2.begin());
        }
        cout << -(s1.begin()->first) << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值