PAT-ADVANCED1112——Stucked Keyboard

我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED

原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805357933608960

题目描述:

题目翻译:

1112 破损的键盘

在破损的键盘上,一些键总是被卡住。因此,当你键入一些句子时,与这些键对应的字符将在屏幕上重复出现k次。

现在,在屏幕上显示结果字符串,您应该列出所有可能的破损键和原始字符串。

请注意,可能会有一些重复键入的字符。无论何时按下,弹出的键总是重复输出固定的k次。例如,当k = 3时,从字符串“thiiis iiisss teeeeeest”我们知道键i和e可能被卡住,但是s不是,因为它有时重复出现有时不是重复出现。 原始字符串可能是“this isss a teest”。

输入格式:

每个输入文件包含一个测试用例。对于每个测试用例,第1行给出正整数k(1 < k <= 100),它是破损键的输出重复次数。第二行包含屏幕上的结果字符串,其中包含来自{a-z},{0-9}和_的不超过1000个字符。题目保证字符串非空。

输出格式:

对每个测试用例,按照检测顺序在一行中打印可能的破损键。确保每个键仅打印一次。然后在下一行打印原始字符串。题目保证至少有一个破损的键。

输入样例:

3
caseee1__thiiis_iiisss_a_teeeeeest

输出样例:

ei
case1__this_isss_a_teest

知识点:字符串

思路:用一个标记数组flag来标记键是否破损

flag数组中的值为0表示该键没出现过,为1表示该键未破损,为2表示该键破损。

第一次遍历字符串时,根据每个字符的重复出现次数确定flag数组中的值。

需要注意的是,在给flag数组赋2时,需要确保之前的值是0,而不是1。因为如果之前已经确认该键未破损的情况下,我们无法因为本次判断来判别其破损。

而对于确认未破损时恰好相反,不管之前的值怎么样,只要本次确认该键未破损,就可以为其相应位置的flag值赋1

第二次遍历字符串时,输出破损的键。在这个过程中,我们需要另一个标记数组output来标记某键是否已被输出,如果已被输出,则不能重复输出。

第三次遍历字符串时,还原出原始输入。对于未破损的键,只需原样输出,而对于破损的键,其输出次数应该除以k。

时间复杂度是O(n),其中n为输入字符串的长度。空间复杂度是O(1001)。

C++代码:

#include<iostream>
#include<cstring>

using namespace std;

int main() {
	int k;
	scanf("%d", &k);
	char input[1001];
	scanf("%s", input);
	int flag[37];	//flag[0] ~ flag[25]代表a-z,flag[26] ~ flag[35]代表0~9,flag[36]代表_
	fill(flag, flag + 37, 0);	//0表示没出现过,1表示没破,2表示破了
	for(int i = 0; i < strlen(input); i++) {
		int count = 1;	//记录当前字符的出现次数 
		while(i + 1 < strlen(input) && input[i + 1] == input[i]) {
			count++;
			i++;
		}
		if(count % k == 0) {	//如果当前字符的出现次数是k的整数倍	
			if(input[i] >= 'a' && input[i] <= 'z') {
				if(flag[input[i] - 'a'] == 0){	//如果该字符没有出现过,则将其flag位置置为2表示破损 
					flag[input[i] - 'a'] = 2;	//如果该字符出现过其flag值是1,那么即使这里出现的次数是k的整数倍,也不应该认为该键破损 
				}
			} else if(input[i] >= '0' && input[i] <= '9') {
				if(flag[input[i] - '0' + 26] == 0){
					flag[input[i] - '0' + 26] = 2;
				}
			} else if(input[i] == '_') {
				if(flag[36] == 0){
					flag[36] = 2;
				}
			}
		} else {
			if(input[i] >= 'a' && input[i] <= 'z') {	//不管之前flag值怎么样,只要出现了不是k的整数倍的次数,该键就不是破损的 
				flag[input[i] - 'a'] = 1;
			} else if(input[i] >= '0' && input[i] <= '9') {
				flag[input[i] - '0' + 26] = 1;
			} else if(input[i] == '_') {
				flag[36] = 1;
			}
		}
	}
	bool output[37];	//表示该键是否已输出过,一个键只输出一次 
	fill(output, output + 37, false);
	for(int i = 0; i < strlen(input); i++) {
		if(input[i] >= 'a' && input[i] <= 'z') {
			if(flag[input[i] - 'a'] == 2 && !output[input[i] - 'a']){
				printf("%c", input[i]);
				output[input[i] - 'a'] = true;
			}
		} else if(input[i] >= '0' && input[i] <= '9') {
			if(flag[input[i] - '0' + 26] == 2 && !output[input[i] - '0' + 26]){
				printf("%c", input[i]);
				output[input[i] - '0' + 26] = true;
			}
		} else if(input[i] == '_') {
			if(flag[36] == 2 && !output[36]){
				printf("%c", input[i]);
				output[36] = true;
			}
		}
	}
	printf("\n");
	for(int i = 0; i < strlen(input); i++) {
		if(input[i] >= 'a' && input[i] <= 'z') {
			if(flag[input[i] - 'a'] == 1) {	//如果当前键不破损,直接打印该字符即可 
				printf("%c", input[i]);
			} else {	
				int count = 1;
				while(i + 1 < strlen(input) && input[i + 1] == input[i]) {
					count++;
					i++;
				}
				for(int j = 0; j < count / k; j++) {	//如果当前键是破损的,打印次数应该是其出现次数除以k 
					printf("%c", input[i]);
				}
			}
		} else if(input[i] >= '0' && input[i] <= '9') {
			if(flag[input[i] - '0' + 26] == 1) {	//如果当前键不破损,直接打印该字符即可 
				printf("%c", input[i]);
			} else {
				int count = 1;
				while(i + 1 < strlen(input) && input[i + 1] == input[i]) {
					count++;
					i++;
				}
				for(int j = 0; j < count / k; j++) {	//如果当前键是破损的,打印次数应该是其出现次数除以k  
					printf("%c", input[i]);
				}
			}
		} else if(input[i] == '_') {
			if(flag[36] == 1) {	//如果当前键不破损,直接打印该字符即可
				printf("%c", input[i]);
			} else {
				int count = 1;
				while(i + 1 < strlen(input) && input[i + 1] == input[i]) {
					count++;
					i++;
				}
				for(int j = 0; j < count / k; j++) {	//如果当前键是破损的,打印次数应该是其出现次数除以k 
					printf("%c", input[i]);
				}
			}
		}
	}
}

C++解题报告:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值