1057 Stack (30)(30 分)
Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<= 10^5^). Then N lines follow, each contains a command in one of the following 3 formats:
Push key\ Pop\ PeekMedian
where key is a positive integer no more than 10^5^.
Output Specification:
For each Push command, insert key into the stack and output nothing. For each Pop or PeekMedian command, print in a line the corresponding returned value. If the command is invalid, print "Invalid" instead.
Sample Input:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
题目要求很简单,统计栈中的中位数输出,因为栈中元素有进有出,所以是在线查询,如果每次调用静态查询(插入删除元素O(N)复杂度)方法肯定超时。可以用分块的思想,N个数据分成
个块,存储并维护每块里边的数字个数,可将每次查询的时间复杂度降为O(
)。
这道题用树状数组是最方便的,时间复杂度为O(logN),个人觉得树状数组也是分块思想的进一步体现,巧妙利用了二进制位的关系存储数据,大大加快了查询速度。值得注意的是当查找中位数时要用二分查找,否则PAT上有一个测试点过不去。
#include<stdio.h>
#include<string>
#include<stack>
using namespace std;
#define MAX 100005
#define lowbit(i) ((i)&(-i))
stack<int> st;
int c[MAX]={0};//BIT
void update(int x,int v){
for(int i=x;i<=MAX;i+=lowbit(i))
c[i]+=v;
}
int getSum(int x){
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=c[i];
return sum;
}
int getMiddle(){//二分查找第一个使getSum(i)大于等于中位数的i
int midcount=(st.size()+1)/2;
int mid=MAX/2,start=1,end=MAX-1;//注意BIT的下标从1开始
int count;
while(mid!=start){
count=getSum(mid);
if(count>=midcount)
end=mid;
else if(count<midcount)
start=mid;
mid=(start+end)/2;
}
if(mid==1&&getSum(1)>=midcount)//特殊情况,栈中只有1(不管多少个)
return 1;
return mid+1;
}
int main(){
int n;
scanf("%d",&n);
char com[50];
for(int i=0;i<n;i++){
scanf("%s",com);
string s(com);
if(s.find("Push")!=s.npos){
int t;
scanf("%d",&t);
st.push(t);
update(t,1);//t的数量加一
}else if(s.find("Pop")!=s.npos){
if(!st.empty()){
update(st.top(),-1);//t的数量减一
printf("%d\n",st.top());
st.pop();
}else
printf("Invalid\n");
}else{
if(!st.empty()){
printf("%d\n",getMiddle());
}else
printf("Invalid\n");
}
}
return 0;
}