https://www.nowcoder.com/pat/5/problem/4110
题意
实现一个栈,在基础功能上,添加一个查找栈中位数的功能。(第(top+1)/2小的那个数)。
思路
一开始我想,由于插入的key不大,可以用一个频率数组num[i],记录小于等于i的栈元素有多少个,每次查找第一个大于等于(top+1)/2的num[i]就是所需要的。
但是呢,我觉得写二分不是我喜欢的。所以写了个暴力for莽了一遍,居然过了两个。
嗯,不过确实不应该逃避自己生疏的知识点。多思考一下确实会有新的收获,比如我今天对lower_bound有了更深的理解。
模拟一下发现,对查找一个存在的数,如果当前元素小于键值,left=mid+1,可以理解为,当前元素不会成为答案,就踢出搜索区间。如果当前元素大于等于键值,其实主要是等于键值的时候,right=mid,因为可能是答案之一,所以就不要把这个数踢出搜索区间。(精细一点应该分三类,偷懒的话就像我下面的写法,分两类就够了)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5+5;
const int INF = 0x3f3f3f3f;
int n;
int num[MAXN];
int stk[MAXN],top;
char op[25];
void add(int x,int val){
while(x<MAXN){
num[x]+=val;
x+=x&-x;
}
}
int ask(int x){
int res=0;
while(x){
res+=num[x];
x-=x&-x;
}
return res;
}
int bit(int x){
int l=1,r=100000,m;
while(l<r){
m=(l+r)>>1;
if(ask(m)<x) l=m+1;
else r=m;//关键
}
return r;
}
int main(){
scanf("%d",&n);
for(int i=1,key;i<=n;i++){
scanf("%s",op);
if(op[1]=='o'){
if(top){
printf("%d\n",stk[top]);
add(stk[top],-1);
top--;
}else puts("Invalid");
}else if(op[1]=='e'){
if(top) printf("%d\n",bit((top+1)/2));
else puts("Invalid");
}else{
scanf("%d",&key);
stk[++top]=key;
add(stk[top],1);
}
}
return 0;
}
/*
*/