1057 Stack (30 分)(C++)

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

解题思路:本题麻烦的地方在于中位数的求法,如果用排序,貌似三个测试点过不了,本题用树状数组,模板什么的也不用多说,树状数组的代码非常非常优雅,短小精悍。

关于树状数组的讲解可以参考这两篇:

https://blog.csdn.net/qq_39553725/article/details/76696168

https://blog.csdn.net/Small_Orange_glory/article/details/81290634

我简单说一下本题怎么用树状数组,本题跟使用树状数组的方式,跟常规还是有点不一样的,首先明确一下,对树状数组c来讲,哪个是索引号,哪个是值?在本题中c的索引号为栈中的值temp,而a数组(没打错,就是a数组,c数组与a数组的关系没理清的,先看看上文的链接)对应的值为该temp值在现在的栈的出现次数,理清楚这个,本题会好很多了。Go on,getsum求的是某个值在现在的栈的所有的值的位置!这里思考一下,假设现在求getsum[temp],我以temp 为 13 来举例:

按照getnum的计算,我们得到的ans = c[13] + c[12] + c[8] 

c[13] = a[13]

c[12] = a[9] + a[10] + a[11] + a[12]

c[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8]

上文说明了a[index]表示index出现次数,那么现在就由 ans 为temp之前的所有数的次数和。

有了这些,现在可以求peekedian了,这里用二分法,但是二分法与常规用的也有些许不同,原因在于,假设我们求到了getsum(mid)为我们需要的target,但是此时的mid未必就是我们找的那个,因为可能这个mid在原栈中根本没有,但是计数的时候由于加的是0,所以恰好getsum(mid)也等于target。

#include <iostream>
#include <stack>
#define lowbit(i) ((i) & (-i))
using namespace std;
const int maxn = 100010;
int c[maxn];
stack<int>s;
void update(int x, int val){
	for(int i = x; i < maxn; i += lowbit(i))
		c[i] += val;
}
int getNum(int x){
	int ans = 0;
	for(int i = x; i >= 1; i -= lowbit(i))
		ans += c[i];
	return ans;
}
int peekMedian(int target){
	int low = 1, high = maxn, mid;
	while(low < high){
		mid = (low + high) / 2;
		if(getNum(mid) < target)
			low = mid + 1;
		else
			high = mid;
	}
	printf("%d\n",low);
}
int main(){
	int n, temp;
	scanf("%d", &n);
	char ch[15];
	for(int i = 0; i < n; ++ i){
		scanf("%s", ch);
		if(ch[1] == 'u'){
			scanf("%d\n", &temp);
			s.push(temp);
			update(temp, 1);
		}
		else if(ch[1] == 'o'){
			if(s.empty())
				printf("Invalid\n");
			else{
				update(s.top(), -1);
				printf("%d\n", s.top());
				s.pop();
			}
		}
		else{
			if(s.empty())
				printf("Invalid\n");
			else
				peekMedian((s.size() + 1) / 2);
		}
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值