POJ_Dynamic Median 数据流的中位数

本文介绍了一种高效算法,用于处理数据流中动态变化的中位数问题。通过使用两个堆(最大堆和最小堆)来维护数据,确保可以在对数时间内插入和删除元素,并在常数时间内获取中位数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dynamic Median

总时间限制: 
3000ms 
内存限制: 
65536kB
描述

设计一个数据结构,初始为空,支持以下操作:

(1)增加一个元素,要求在log(n)时间内完成,其中n是该数据结构中当前元素的个数。注意:数据结构中允许有重复的元素。

(2)返回当前元素集合的中位数,要求在常数时间内完成。如果当前元素的个数为偶数,那么返回下中位数(即两个中位数中较小的一个)。

(3)删除中位数,要求在log(n)时间内完成。


输入
输入的第一行是一个自然数T,代表测试数据的组数((1 ≤ T ≤ 600))。每组测试数据的第一行是个自然数N,代表操作的次数,1<=N<=10000。后面的N行中的每行代表一个操作,每次操作首先输入一个单字符代表操作的类型:

I表示插入,后面跟着输入一个正整数(这是唯一带有输入数值的操作)。
Q表示查询,输出当前的中位数(这是唯一产生输出的操作)。
D表示删除当前的中位数。

输入保证是正确的:查询时集合保证不为空(即中位数是存在的),删除时保证集合中有足够可供删除的元素。
输出
每次查询操作Q时输出的中位数,每次输出单独占一行。
样例输入
1
8
I 4
I 3
I 5
Q  
D
I 10
I 2
Q
样例输出
4
3
提示
123
来源
课程

思路:这是一个剑指offer书上的一道题目。题目意思是让你找到输入的数据流中的最大的中位数,并且偶数的时候返回较小的。用两个连在一起的堆可以实现这个算法,具体是一个最大堆,一个最小堆,其中在数据插入的过程中保证最大堆的最大值要小于最小堆的最小值。这样数据被切分成了两个部分,同时保证,最大堆的size比最小堆的size大于等于1(奇数情况下),偶数情况下相等,这样 中位数是最大堆的最大值。
在删除的过程中,同时要保证堆的size信息。
数据流的题目涉及到数据量比较大,类似的题目有一个很大的数据流,去找该数据流中前k个最大的数,用一个大小为k的最小堆,这样在数据流入是保证每个数据都比最小堆的最小值小,否则就插入该元素,把之前最小的删除。
提示:!!!!!!!!!!!!!!!!!
这道题目用cin cout 会超时,不管你加不加std::ios::sync_with_stdio(false);,都会超时。

AC code:
#include <iostream>
#include<stdio.h>
#include <queue>
#include <vector>
using namespace std;
priority_queue<int, vector<int>, less<int> > p;  //最大堆
priority_queue<int, vector<int>, greater<int> > q;  //最小堆

void insert(int num){
	if(p.empty())
		p.push(num);
	else {
		if(num < p.top())
		p.push(num);
		else 
		q.push(num);
	
	}
	if(p.size() - 2 == q.size())
	{
		q.push(p.top());
		p.pop();
	}
	if(p.size() +1 == q.size()){
		p.push(q.top());
		q.pop();
	}
}
int getMedian(){
	printf("%d\n",p.top()); 
}
void deleteNum(){
	p.pop();
	if(p.size() + 1 == q.size())
	{
		p.push(q.top());
		q.pop();
	}
}
void clear(){
	while(!q.empty()) q.pop();
	while(!p.empty()) p.pop();
}
int main(){
	//freopen("B.txt","r",stdin);
	//std::ios::sync_with_stdio(false);
	int t,n,num; 
	char c;
	scanf("%d",&t);
	while(t--){
		clear();
		scanf("%d",&n); 
		while(n--){
			scanf("%c",&c);
			scanf("%c",&c);
			if(c=='I'){
				scanf("%d",&num);
				insert(num);
			}
			else if(c=='Q'){
				getMedian();
			}else {
				deleteNum();
			}				
		}
	}	
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值