PAT 1057. Stack

入栈、出栈的操作都好说,就是PeekMedian麻烦,不能每次都重新排序了数过来。

然后因为题目说了“key is a positive integer no more than 105”,所以我们可以用一个整型数组来保存栈里每种数字的个数。我将其命名为amount[],amount[0]=数字0的个数

amount[1]=数字1的个数……

这样,要执行 PeekMedian指令时,先看当前栈的容量,容量为k,则我们要找的就是大小排在第(k/2)的数。

假设amount[0]+amount[1]+amount[2]+……+amount[i]的总和叫做Si,显然Si表示:栈中数值小于或等于i的数字的个数。

如果S(i-1)<(k/2),且Si>=(k/2),则栈中大小排在第(k/2)的数的值等于i。

寻找正确的i,以使S(i-1)<(k/2)且Si>=(k/2),这个寻找的过程必须是二分的。

判断一个i值是否满足S(i-1)<(k/2)、Si>=(k/2)的时候,需要计算S(i-1)和Si,这个过程也很耗时,需用树状数组提速。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=100005;
int stak[N];
int tail=0;
int amount[N]={0};
int mid;
void dele(int x){
	if(x<=0)return;
	while(x<N){
		amount[x]--;
		x+=(x&-x);
	}
}
void adda(int x){
	if(x<=0)return;
	while(x<N){
		amount[x]++;
		x+=(x&-x);
	}
}
int calcu(int x){
	if(x<=0)return 0;
	int re=0;
	while(x>0){
		re+=amount[x];
		x-=(x&-x);
	}
	return re;
}
void found(int sum){
	int lf=0,rt=N-3,mid=(lf+rt)/2;
	int temp1,temp2;
	while(1){
		temp1=calcu(mid-1);
		temp2=calcu(mid);
		if(temp1<sum&&temp2>=sum)break;
		
		if(temp1>=sum)
			rt=mid;
		else if(temp2<sum)
			lf=mid+1;
		mid=(lf+rt)/2;
	}
	printf("%d\n",mid);
}
int main(){
	int n,i;
	scanf("%d",&n);
	char order[30];
	while(n--){
		scanf("%s",order);
		if(strcmp(order,"Pop")==0){
			if(tail==0)
				printf("Invalid\n");
			else{
				dele(stak[tail-1]);
				printf("%d\n",stak[--tail]);
			}
		}
		else if(strcmp(order,"PeekMedian")==0){
			if(tail==0)
				printf("Invalid\n");
			else{
				if(tail%2==1)
					found(tail/2+1);
				else
					found(tail/2);			
			}
		}
		else if(strcmp(order,"Push")==0){
			scanf("%d",&stak[tail++]);
			adda(stak[tail-1]);		
		}
	}
return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值