查询无序数组中第M小的数,期间不断插入、删除,每次查询都排序一次的代价太大。
以最大可能取值maxn为范围,将数字分成ceil(sqrt(maxn))组,每组floor(sqrt(maxn))个数,另外设置两个数组,一个统计每个数字出现的次数,另一个统计每个组中数字的个数。
查询时,首先确定在哪个块,再在该块中找第M个。
#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
const int maxn = 100001;
const int blk = 317;
const int blk_size = 316;
int N;
stack<int> s;
int num_count[maxn]={
}; //每个数的个数
int blk_count[blk]={
}; //每个块中数的个数
int findMedian();
int main(){
scanf("%d", &N);
while(N--){
char command[15];
scanf("%s", command);
if(strcmp(command, "Push")==0){
int v;
scanf("%d", &v);
s.push(v);
num_count[v]++;
blk_count[v/blk_size]++;
}
else if(strcmp(command, "Pop")==0){
if(s.empty()) printf("Invalid\n");
else{
int v = s.top();
printf("%d\n", v);
s.pop();
num_count[v]--;
blk_count[v/blk_size]--;
}
}
else{
if(s.empty()) printf("Invalid\n");
else printf("%d\n", findMedian());
}
}
return 0;
}
int findMedian(){
int n = s.size();
int M = (n%2==0)?(n/2):((n+1)/2);
int sum = 0;
for(int b=0; b<blk; b++){
if(sum+blk_count[b]<M){
sum += blk_count[b];
continue;
}
else{
for(int i=b*blk_size; i<(b+1)*blk_size; i++){
if(sum+num_count[i]<M){
sum += num_count[i];
continue;
}
else return i;
}
}
}
}