【优先队列/对顶】Running Median

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After each odd-indexed value is read, output the median (middle value) of the elements received so far. 

输入描述:

The first line of input contains a single integer P(1≤P≤1000)P(1 \leq P  \leq 1000)P(1≤P≤1000), which is the number of data sets that follow. The first line of each data set contains the data set number, followed by a space, followed by an odd decimal integer M(1≤M≤9999)M (1  \leq M  \leq 9999)M(1≤M≤9999), giving the total number of signed integers to be processed. The remaining line(s) in the dataset consists of the values, 10 per line, separated by a single space. The last line in the dataset may contain less than 10 values.

输出描述:

For each data set the first line of output contains the data set number, a single space and the number of medians output (which should be one-half the number of input values plus one). The output medians will be on the following lines, 10 per line separated by a single space. The last line may have less than 10 elements, but at least 1 element. There should be no blank lines in the output.

示例1

输入

复制3 1 9 1 2 3 4 5 6 7 8 9 2 9 9 8 7 6 5 4 3 2 1 3 23 23 41 13 22 -3 24 -31 -11 -8 -7 3 5 103 211 -311 -45 -67 -73 -81 -99 -33 24 56

3 
1 9 
1 2 3 4 5 6 7 8 9 
2 9 
9 8 7 6 5 4 3 2 1 
3 23 
23 41 13 22 -3 24 -31 -11 -8 -7 
3 5 103 211 -311 -45 -67 -73 -81 -99 
-33 24 56

输出

复制1 5 1 2 3 4 5 2 5 9 8 7 6 5 3 12 23 23 22 22 13 3 5 5 3 -3 -7 -3

1 5
1 2 3 4 5
2 5
9 8 7 6 5
3 12
23 23 22 22 13 3 5 5 3 -3 
-7 -3

翻译

题目描述: 对于这个问题,你需要编写一个程序,读取一系列32位有符号整数。在每次读取到奇数索引值时,输出目前接收到的元素的中位数(中间值)。

输入描述: 输入的第一行包含一个整数 P(1≤P≤1000),表示数据集的数量。每个数据集的第一行包含数据集编号,后跟一个空格,然后是一个奇数十进制整数 M(1≤M≤9999),表示要处理的有符号整数的总数。数据集的其余行由值组成,每行有10个值,用单个空格分隔。数据集的最后一行可能包含少于10个值。

输出描述: 对于每个数据集,输出的第一行包含数据集编号,后跟一个空格和输出的中位数数量(应为输入值数量的一半加一)。下面是输出的中位数,每行10个值,用单个空格分隔。最后一行可能少于10个元素,但至少有1个元素。输出中不应有空行。

 解题思路

  1. 创建一个最大堆 maxHeap 和一个最小堆 minHeap(我这里为方便名字用的p,q),大根堆维护序列较小的一半,小根堆维护较大的一半。
  2. 将第一个整数作为基准值(记为 mid)放入最大堆。
  3. 遍历剩余的整数:
    • 如果当前整数小于等于基准值 mid,将其插入最小堆 minHeap 中。
    • 如果当前整数大于基准值 mid,将其插入最大堆 maxHeap 中。
  4. 检查堆的大小,保证最大堆的大小等于或比最小堆的大小多一。如果不满足,则调整堆的大小,即将最大堆的根节点弹出并插入到最小堆中,或将最小堆的根节点弹出并插入到最大堆中。
  5. 输出当前接收到的元素的中位数。中位数可以通过最大堆和最小堆的根节点来获得。

 详细代码:

#include<iostream>
#include<math.h>
#include<vector>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
typedef int ll;
using namespace std;
priority_queue<int, vector<int>, greater<int> >q;//最小堆
priority_queue<int, vector<int>>p;//最大堆
int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int P;
    P = read();
    while (P--)
    {
        while (!q.empty())q.pop();
        while (!p.empty())p.pop();
        int index, num, m;
        index = read();num = read();
        printf("%d %d\n", index, (num + 1) / 2);
        p.push(read());//奇数索引放入最小堆
        printf("%d ", p.top());//输出第一个值
        for (int i = 2;i <= num;i++)
        {
            int a = read();
            if (a <= p.top())p.push(a);
            else q.push(a);
            int g = q.size(), l = p.size();
            if (g > l + 1) { p.push(q.top());q.pop(); }
            //确保最大堆的大小大于等于最小堆加1,不满足则调节
            else if (l > g) { q.push(p.top()); p.pop(); }//记得把移动的数删掉
            if (i & 1) {
                g = q.size(), l = p.size();
                // printf("g=%d l=%d ",g,l);
                if (g >= l)printf("%d ", q.top());
                else printf("%d ", p.top());
                if (i % 20 == 19 && i != num)printf("\n");//换行
            }
        }
        printf("\n");//有点重要的换行
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值