洛谷 1168 中位數
題目描述
給出一個長度爲NN的非負整數序列A_iAi,對於所有1≤k≤(N+1)/2,輸出A1,A3,…,A2k−1的中位數。即前1,3,5,…個數的中位數。
輸入格式
第1行爲一個正整數N,表示了序列長度。
第2行包含N個非負整數Ai(Ai≤10^9)。
輸出格式
共(N+1)/2行,第i行爲A1,A3,…,A2k−1的中位數。
輸入輸出樣例
輸入
7 1 3 5 7 9 11 6
輸出
1 3 5 6
說明/提示
對於20\%20%的數據,N ≤ 100N≤100;
對於40\%40%的數據,N ≤ 3000N≤3000;
對於100\%100%的數據,N ≤ 100000N≤100000。
解析:
使用兩個堆,大根堆維護較小的值,小根堆維護較大的值,即大根堆的堆頂是較小的數中最大的,小根堆的堆頂是較大的數中最小的
將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆,那麼就保證了所有大根堆中的元素都小於小根堆中的元素
於是我們發現對於大根堆的堆頂元素,有【小根堆的元素個數】個元素比該元素大,【大根堆的元素個數-1】個元素比該元素小;同理,對於小跟堆的堆頂元素,有【大根堆的元素個數】個元素比該元素小,【小根堆的元素個數-1】個元素比該元素大;
那麼維護【大根堆的元素個數】和【小根堆的元素個數】差值不大於1之後,元素個數較多的堆的堆頂元素即爲當前中位數;(如果元素個數相同,那麼就是兩個堆堆頂元素的平均數,本題不會出現這種情況)
根據這兩個堆的定義,維護方式也很簡單,把元素個數多的堆的堆頂元素取出,放入元素個數少的堆即可
AC代碼:
#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int> >Q1;//大根堆,維護較小的數值
priority_queue<int,vector<int>,greater<int> >Q2;//小根堆,維護較大的數值
int main(){
int n,x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(!Q1.empty()&&x<=Q1.top()) Q1.push(x);
else if(!Q2.empty()&&x>Q2.top()) Q2.push(x);
else Q2.push(x);
//調整堆的大小,滿足(小頂堆元素個數)-(大頂堆元素個數)= 1
if(Q1.size()>Q2.size()){
Q2.push(Q1.top());
Q1.pop();
}
else if(Q2.size()>Q1.size()+1){
Q1.push(Q2.top());
Q2.pop();
}
if(i%2==1) printf("%d\n",Q2.top());
}
return 0;
}