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; }
-