pat a1057 栈【分块思想】

本文介绍了一种使用栈数据结构实现基本操作(Push、Pop)的同时,能够高效查询当前栈内元素中位数的方法。通过将元素分布于多个预定义大小的桶中,并维护每个桶内的元素计数,可以快速定位到中位数所在的桶,进而找到确切的中位数值。此方法适用于大量数据的实时中位数查询场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

https://www.nowcoder.com/pat/5/submission-detail/64563013

https://pintia.cn/problem-sets/994805342720868352/problems/994805417945710592

一、问题描述

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

 给出一个栈的入栈(Push)、出栈(Pop)过程,并随时通过PeekMedian命令要求输出栈中中间大小的数(Pop命令输出出栈的数)。当栈中没有元素时,Pop命令和PeekMedian命令都应该输出Invalid。

二、算法实现 

1、

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

const int maxn=100010;
const int sqrN=316;

stack<int> st;
int block[sqrN];
int table[maxn];

void peekMedian(int K)
{
	int sum=0;
	int idx=0;  //块号 
	while(sum+block[idx]<K)
	{
		sum+=block[idx++];
	}
	int num=idx*sqrN;
	while(sum+table[num]<K)
	{
		sum+=table[num++];
	} 
	printf("%d\n",num);
}

void Push(int x)
{
	st.push(x);
	block[x/sqrN]++;
	table[x]++;
}

void Pop()
{
	int x=st.top();
	st.pop();
	block[x/sqrN]--;
	table[x]--;
	printf("%d\n",x);	
}

int main()
{
	int x,query;
	memset(block,0,sizeof(block));
	memset(table,0,sizeof(table));
	char cmd[20];
	scanf("%d",&query);
	
	for(int i=0;i<query;i++)
	{
		scanf("%s",cmd);
		if(strcmp(cmd,"Push")==0)
		{
			scanf("%d",&x);
			Push(x);
		}
		else if(strcmp(cmd,"Pop")==0)
		{
			if(st.empty()==true)
			{
				printf("Invalid\n");
			}
			else
			{
				Pop();
			}
		}
		else
		{
			if(st.empty()==true)
			{
				printf("Invalid\n");
			}
			else
			{
				int K=st.size();
				if(K%2==1) K=(K+1)/2;
				else K=K/2;
				peekMedian(K);
			}
		}		
	}
	return 0;
}

2、

#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
const int MAX = 100001;
const int MAXN = 317;
int n, block[MAXN] = {0}, table[MAX] = {0};
char order[11];
stack<int> s;
 
bool cmp(int a, int b)
{
	return a < b;
}
 
int main()
{
	scanf("%d", &n);
	while(n--)
	{
		scanf("%s", order);
		if(strcmp(order, "Pop") == 0)
		{
			if(!s.empty())
			{
				int k = s.top();
				printf("%d\n", k);
				s.pop();
				block[k/(MAXN-1)]--;
				table[k]--;
			}
			else printf("Invalid\n");
		}
		else if(strcmp(order, "PeekMedian") == 0)
		{
			if(s.empty())
			{
				printf("Invalid\n");
				continue;
			}
			int k, idx = 0, index = 0;
			if(s.size() % 2 == 0) k = s.size()/2;
			else k = (s.size()+1)/2;
			int sum = 0;			
			while(sum + block[idx] < k)
			{
				sum += block[idx++];
			}
			index = idx * (MAXN-1);
			while(sum + table[index] < k)
			{
				sum += table[index++];
			}
			printf("%d\n", index);
		}
		else
		{
			int k;
			scanf("%d", &k); 
			s.push(k);
			table[k]++;
			block[k/(MAXN-1)]++;
		}
	}
	return 0;
}

 

### PAT乙级1057题目解析 对于PAT乙级1057题,其核心需求是对科学计数法表示的实数进行转换并输出为普通的数字表示形式。以下是对此类问题的具体分析以及解决方案。 #### 题目要求 每个输入包含一个测试用例,即一个以科学计数法表示的实数 \( A \)。该数字的存储长度不超过9999字节,且其指数的绝对值不超过9999。需要按照普通数字表示法输出 \( A \),并确保所有有效位都被保留,包括末尾的0[^1]。 #### 解决方案 为了实现这一目标,可以采用字符串处理的方式完成科学计数法到普通数字表示法的转换: 1. **提取符号、基数和指数部分** 科学计数法的标准格式通常为 `±X.YYZe±N` 或 `±X.YYZE±N`,其中: - 符号部分可能为空或为正负号; - 基数部分由整数部分和小数部分组成; - 指数部分决定小数点移动的方向和步数。 2. **调整小数点位置** 根据指数的正值或负值,向右或向左移动小数点的位置。如果指数较大导致前导零增加,则需补充相应数量的零;反之亦然。 3. **保持精度** 转换过程中应特别注意保留原始数据中的所有有效位,尤其是小数部分的末尾零。 下面是基于Python的一个具体实现方法: ```python def scientific_to_decimal(scientific_str): sign, decimal_part, exponent_sign, exponent_value = '', '', '', '' # 判断是否有符号 if scientific_str[0] in "+-": sign = scientific_str[0] scientific_str = scientific_str[1:] # 提取基数部分 base, exp = scientific_str.split('E') if 'E' in scientific_str else scientific_str.split('e') integer_part, fractional_part = base.split('.') if '.' in base else (base, '') # 处理指数部分 exponent_sign = '+' if exp[0] not in '+-' else exp[0] exponent_value = int(exp[1:]) if exponent_sign == '+' else -int(exp[1:]) # 小数点移位逻辑 result = "" if exponent_sign == '+': if len(fractional_part) >= exponent_value: result = integer_part + fractional_part[:exponent_value] + "." + fractional_part[exponent_value:] if fractional_part[exponent_value:] != "" else "" else: result = integer_part + fractional_part.ljust(exponent_value, '0') elif exponent_sign == '-': result = "0." + ("0" * abs(exponent_value))[:-len(integer_part)] + integer_part + fractional_part return f"{sign}{result.strip('.')}" # 测试函数 print(scientific_to_decimal("+1.23400E-03")) # 输出: 0.00123400 ``` 上述代码实现了从科学计数法到普通数字表示法的精确转换,并妥善处理了各种边界情况,如指数过大或过小时的小数点定位及补零操作。 #### 注意事项 在实际编程竞赛环境中,还需考虑一些特殊场景下的表现,比如极端的大数值或者非常规输入格式等问题。因此建议多尝试不同类型的测试案例来验证程序稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值