1057.Stack

【题意】
        在一般的栈的基础上,增加一个取中位数的功能

【思路】
        1.    采用树状数组记录数字出现次数的部分和
        2.    用两个集合(要用multiset)存储高低两部分的数,在Push和Pop后保证高部分的set至少比低部分的多1个,至多多2个(除非都是空的),这样取高部分的第一个数即是中位数了
        3.    我本来的思路是用一个vector模拟栈,然后在要取中位数时排序并输出,但这样会在三个点超时。另外我也试过直接用stack,并用一个multiset存数字,但这样无法在O(1)时间内找到中位数(set不支持随机取数),依然会超时

【注意点】

        无论用何种方法,都需要scanf读和printf写,否则会超时


用树状数组解:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <stack>
using namespace std;

#define MAXKEY 100000

int c[MAXKEY+1];

int lowbit(int x){
	return x&(-x);
}

void add(int index, int num){
	while(index<=MAXKEY){
		c[index] += num;
		index += lowbit(index);
	}
}

int sum(int index){
	int res = 0;

	while(index){
		res += c[index];
		index -= lowbit(index);
	}

	return res;
}

int findIndex(int n){
	int left,right,mid;

	left = 1;
	right = MAXKEY;
	while(left<right){
		mid = (left+right)/2;
		if(sum(mid)<n){
			left = mid+1;
		}
		else{
			right = mid;
		}
	}

	return left;
}

int main(int argc, char const *argv[])
{
	stack<int> ss;
	int n;

	memset(c,0,sizeof(c));
	scanf("%d", &n);
	while(n--){
		char command[11];
		scanf("%s", command);
		if(strcmp(command,"Push")==0){
			int num;
			scanf("%d", &num);
			add(num,1);
			ss.push(num);
		}
		else if(strcmp(command,"Pop")==0){
			if(ss.empty()){
				printf("Invalid\n");
			}
			else{
				printf("%d\n", ss.top());
				add(ss.top(),-1);
				ss.pop();
			}
		}
		else{
			if(ss.empty()){
				printf("Invalid\n");
			}
			else{
				printf("%d\n", findIndex((ss.size()+1)/2));\
			}
		}
	}

	system("pause");
	return 0;
}


用两个multiset快速找到中位数:

#include <iostream>
#include <stack>
#include <set>
#include <functional>
#include <cstdio>
#include <cstring>
using namespace std;

int main(int argc, char const *argv[])
{
	stack<int> st;
	multiset<int> upper;
	multiset<int,greater<int>> lowwer;
	int n;

	scanf("%d", &n);
	while(n--){
 		char command[11];
 		int num;
		
 		scanf("%s", command);
 		if(strcmp(command,"Pop")==0){
 			if(st.empty()){
 				printf("Invalid\n");
 			}
 			else{
 				printf("%d\n", st.top());
 				if(*upper.begin()<=st.top()){
 					upper.erase(upper.find(st.top()));
 				}
 				else{
 					lowwer.erase(lowwer.find(st.top()));
 				}
 				st.pop();
 				if(upper.size()==lowwer.size() && lowwer.size()>0){
 					upper.insert(*(lowwer.begin()));
 					lowwer.erase(lowwer.begin());
 				}
 				else if(upper.size()-lowwer.size()>2){
 					lowwer.insert(*upper.begin());
 					upper.erase(upper.begin());
 				}
 			}
 		}
 		else if(strcmp(command,"Push")==0){
 			scanf("%d", &num);
 			st.push(num);
 			if(lowwer.size()>0 && *lowwer.begin()>st.top()){
 				lowwer.insert(st.top());
 			}
 			else{
 				upper.insert(st.top());
 			}
 			if(upper.size()==lowwer.size()){
 				upper.insert(*(lowwer.begin()));
 				lowwer.erase(lowwer.begin());
 			}
 			else if(upper.size()-lowwer.size()>2){
 				lowwer.insert(*upper.begin());
 				upper.erase(upper.begin());
 			}
 		}
 		else{
 			if(st.empty()){
 				printf("Invalid\n");
 			}
 			else{
 				printf("%d\n", *upper.begin());
 			}
 		}
	}

	system("pause");
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值