PAT 1057 Stack C++版

版权声明:如若转载,请联系作者。 https://blog.csdn.net/liu16659/article/details/89480988

PAT 1057 Stack C++版

1.题意

给出一系列栈的操作,让我们模拟动态查询(即在线查询)
本体的在线查询主要是找出中位数,即一个数组中中间的那个数。关于一个数组中中间数的定义如下:

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.

因为N的值比较大(N= 10^5),所以很难进行一遍排序,然后再找出其中间的那个数。故这里提供如下两种思路:

2.分析

2.1 分块思想

这个思想比较简单。使用如下的例子来说明:
假设现在有5个数(1, 2 , 3 , 4, 5)需要进行排序,找出其中的中间数。如何使用分块的思想实现呢?

  • step 1: 分块
    分块的过程至关重要!
    我们首先将这个 5个元素分成3(ceil(sqrt(5)) = 3)块,而且每块有ceil(sqrt(5))个元素 **[虽然这里的总数已经超过了5,但是便于计算而且不影响结果的生成,其实块数和每块的个数不影响结果] ** ,然后剩下的元素就放在最后一组里。
    针对上面的数字,我们得到的分块分别是
    block[0] = {1,2}block[1] = {3,4}block[2] = {5}

  • step 2:
    针对每个元素使用一个数组table[n]进行一个计数操作,table[i]表示的就是i这个元素的个数。
    针对上面的数据,得到的结果就是:

table[1] = 1, table[2] = 1, table[3] = 1, table[4] = 1, table[5] = 1
  • step 3: 对块和table进行操作
    例如,如果是Push 3,则表示需要往block[3/2],即block[1]中添加一个元素,这样block[1] = 3; 同时将 table[3]++; 如果是Pop操作,则进行逆操作即可。

  • step 4:找中间数
    首先找根据block 的数量确定在哪个block里;找到所在的block之后,再根据table确定相应的数据即可。

3.代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<stack> 

#define maxn 100001//表示最多有15 [1 - 15] 个整数 
#define sqrN 317 //表示最大有317组 

using namespace std;

int N;
stack<int> sta;//用于装数字的栈	
int table[maxn];//table[i] 表示的就是i这个元素的个数 
int block[sqrN];//表示每组的所有数的个数 
int total ;//表示当前的栈中的所有元素 

//寻找中间数 
void findMid(){
	total = sta.size();//得到栈中的所有元素
	int mid ;// 中间数 
	if(total % 2 == 0) {//如果为偶数 
		mid = total/2; 
	}else{
		mid = (total+1)/2; 
	}
	int i;
	
	//开始遍历找到中间数 
	int sum = 0; 
	for(i = 0;i < 317;i++){//注意这里i的上限是个定值 ,在这里是4		
		if(sum + block[i] < mid){//如果加上当前的组数还未到 
			sum += block[i];//则加上 
		}
		else{
			break;//跳出循环 
		} 
	}
	//说明在下标为i的block中, 能够找到中间数
	int startNum ,endNum ; //开始数和截止数 
	startNum = i * 317;
	endNum = (i + 1) * 317; 
	for(int j = startNum; j < endNum;j++){
		if(sum + table[j] < mid){
			sum += table[j];
		}
		else {
			cout << j <<"\n";
			break;//说明找到中间数了 
		}
	}	
}

//针对给出的字符串进行操作 
void ope(string str){	
	//Pop PeekMedian Push	
	int tempNum;// 表示当前需要处理的数字(数字) 
	string strNum;// 表示当前需要处理的数字 (字符串) 
	
	if(str.compare("Pop") == 0){//说明是出栈操作 
		if(sta.size() > 0){//如果有元素出栈 
			tempNum = sta.top();//栈顶元素
			table[tempNum] --;//该元素数目减1 
			block[tempNum/317] -- ;//该大组数目减1 
			sta.pop();//将头元素出栈
			cout << tempNum <<"\n";//将栈顶元素出栈				
		}
		else cout << "Invalid\n";		
	}
	else if (str.compare("Push") == 0){//说明是入栈栈操作 
		cin >> tempNum;//输入需要入栈的数 
		sta.push(tempNum);//将头元素入栈
		table[tempNum]++;
		block[tempNum/317]++;
	}
	else{//说明需要打印中间数 
		if(sta.size() > 0)//如果栈中有元素
			findMid();		
		else cout << "Invalid\n";		
	}	
}

int main(){	
	int i ,j;
	string str; 
	cin >> N;	
	for(i = 0;i < N;i++){		
		cin >> str;	//进行简单的输入		
		ope(str);//执行相应的操作 
	}		
} 

4.测试用例

18
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
Push 4293 
PeekMedian
Pop
Pop
Pop
Pop

6
Push 11
Push 2
Push 3 
PeekMedian
Pop
PeekMedian 

猜你喜欢

转载自blog.csdn.net/liu16659/article/details/89480988