PAT-1057 Stack

 

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个数据分成 \large \left \lfloor \sqrt{N} \right \rfloor 个块,存储并维护每块里边的数字个数,可将每次查询的时间复杂度降为O(\large \sqrt{N})。

    这道题用树状数组是最方便的,时间复杂度为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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值