思路
题意是,依次读取数列,并输出前奇数个数字的中位数。就是找中间大的那个数,设为 mid,左边全都小于等于mid,右边全都大于等于mid,这不就是2个堆吗?左边是个大根堆,右边是个小根堆。如果2个堆中元素数量不同,就来回移动直到2个堆的元素书一半多,这时,mid就是中位数了。
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int N=1e5+10;
int n,d[N],mid;
priority_queue<int,vector<int>,less<int> >q1;//大根
priority_queue<int,vector<int>,greater<int> >q2;//小根
int main(){
scanf("%d",&n);
scanf("%d",&d[0]);
mid=d[0];
printf("%d\n",mid);
for(int i=1;i<n;i++){
scanf("%d",&d[i]);
if(d[i]>mid) q2.push(d[i]);
else q1.push(d[i]);
if(i%2==0){
while(q1.size()!=q2.size()){
if(q1.size()>q2.size()){
q2.push(mid);
mid=q1.top();
q1.pop();
}
else{
q1.push(mid);
mid=q2.top();
q2.pop();
}
}
printf("%d\n",mid);
}
}
return 0;
}
此题还可以用vector解决
用 v.insert(upper_bound(v.begin(),v.end(),x),x)
来二分插入数据,这样有效降低时间复杂度,否则每次插入一个数,就整体排序一次,肯定要超时了。但这么做仍然比上面的优先队列慢,原因是:插入位置虽然用二分查找了,但插入这个动作还是会造成插入位置后的元素整体后移,这使用了大量的时间。
#include <cstdio>、
#include <algorithm>
#include <vector>
using namespace std;
int n;
vector<int> v;
int main(){
scanf("%d",&n);
for(int i=0,x;i<n;i++){
scanf("%d",&x);
v.insert(upper_bound(v.begin(),v.end(),x),x);
if(i%2==0){
printf("%d\n",v[i/2]);
}
}
return 0;
}
虽然这种方法比优先队列慢,但也提供一种用vector模拟set 的一种思路。因为set是没有下标的,用vector模拟set后确是有下标的。
参考: 链接