比较经典的一道题,以前在洛谷上做到过。
题意:
(原题是英文)
给出n个数字,n为奇数。依次读入这些数字,读入奇数个数的时候,输出当前已输入的数字中的中位数。
注意题目有多组数据。
思路:
算是套路题吧。
我们可以利用两个堆来维护中位数,具体的操作是这样的:
维护一个大顶堆一个小顶堆,接着我们每次维护当前的中位数x,保证大顶堆中的数都小于x,小顶堆中的数都大于等于x。
每次读入2个数,如果这两个数都比x要大,我们放入比x大的小顶堆中。接着我们把x放入大顶堆,从小顶堆中弹出堆顶元素就是新的中位数;
同理,如果这两个数比x要小,我们放入比x小的大顶堆中。接着我们把x放入小顶堆,从大顶堆中弹出堆顶元素作为新的中位数;
如果x介于两数中间,把小数放入大顶堆,大数放入小顶堆,中位数不变。
这样子我们相当于花O(n)扫了一遍读入的数字,每次维护堆中元素需要花费2*logn时间。
总时间复杂度可以认为是O(nlogn)
代码:
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q2; //小顶堆
priority_queue<int,vector<int>,less<int> >q1; //大顶堆
int main()
{
int T;
cin>>T;
while(T--){
while(!q1.empty())q1.pop();
while(!q2.empty())q2.pop();
int idx,n;
scanf("%d%d",&idx,&n);
printf("%d %d\n",idx,n/2+1);
int x,now,t=0;
scanf("%d",&x);
t++;
now=x;
printf("%d ",now);
for(int i=1;i<=n/2;i++){
int x,y;
scanf("%d%d",&x,&y);
t++;
if(x>y)swap(x,y);
if(x>now){
q1.push(now);
q2.push(x);
q2.push(y);
now=q2.top();
q2.pop();
printf("%d ",now);
}
else if(y<now){
q2.push(now);
q1.push(x);
q1.push(y);
now=q1.top();
q1.pop();
printf("%d ",now);
}
else {
q1.push(x);
q2.push(y);
printf("%d ",now);
}
if(t%10==0)cout<<endl;
}
if(t%10)cout<<endl;
}
return 0;
}
京公网安备 11010502036488号