whenever

  • Home

  • Tags21

  • Categories6

  • Archives122

  • About

PAT乙级1029 || 旧键盘(详解,C/C++示例,测试点分析)

Posted on 2019-09-06 In PAT

旧键盘

题目描述

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。

输入格式

输入在 2 行中分别给出应该输入的文字、以及实际被输入的文字。每段文字是不超过 80 个字符的串,由字母 A-Z(包括大、小写)、数字 0-9、以及下划线 _(代表空格)组成。题目保证 2 个字符串均非空。

输出格式

按照发现顺序,在一行中输出坏掉的键。其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有 1 个坏键。

输入样例

1
2
7_This_is_a_test
_hs_s_a_es

输出样例

1
7TI

问题解决

解题思想

本题设置了一个标记数组str_hash[],将字符0-9散列到数组str_hash[]下标0-9,将字符A-Z或a-z散列到数组str_hash[]下标10-35,对于散列之后对应的下标ha,str_hash[ha]为0表示散列前对应的字符还未输出;str_hash[ha]为1表示散列前对应的字符已经输出,就不再重复输出;将下划线单独处理。注意下标的移动问题,若a[i] != b[j],则a[i]一定是坏键,此时只需将i后移一位;若a[i] = b[j],则a[i]不是坏键,此时i与j都需要后移一位。由于某一字母是坏键时(无论大写还是小写字母)只需输出大写字母,只需将小写字母转换成大写字母,然后再进行散列即可。

易错提醒

示例代码中,若将第13行的while循环判断条件改成:

1
while(a[i] != '\0'&&b[j] != '\0')

将导致最后一个测试点不通过,因为实际输入的文字串结束而应该输入的文字串未结束时,应该输入的文字串后面可能还会有一些坏键,由于循环已经退出,它们将不能输出,从而导致错误。

若将第37行的i后移去掉,改成如下形式代码(i后移放到每一判断条件内部):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <cstdio>
#define MAXN 81
using namespace std;
int main()
{
char a[MAXN],b[MAXN]; //a[]为应该输入的文字,b[]为实际输入的文字
int str_hash[36] = {0}; //通过散列的方式标记某一坏掉的键是否已输出
int flag = 1; //单独标记下划线是否已输出(若下划线为坏掉的键)
scanf("%s",a); //输入应该输入的文字
getchar(); //吸收掉换行
scanf("%s",b); //输入实际输入的文字
int i = 0,j = 0;
while(a[i] != '\0'){ //注意此处的条件
if(a[i] != b[j]){
if(flag&&a[i] == '_'){ //'_'为坏键且还未输出
printf("_");
flag = 0; //标记'_'已输出
i++; //应输入文字串的下标后移一位
}
else if((a[i] >= 'a'&&a[i] <= 'z')
||(a[i] >= 'A'&&a[i] <= 'Z')){ //小写或大写字母
if(a[i] >= 'a'&&a[i] <= 'z'){ //若为小写字母
a[i] -= 32; //转换成大写字母
}
int ha = a[i] - 55; //散列,'A'散列对应下标10
if(str_hash[ha] == 0){ //之前未输出过
printf("%c",a[i]);
str_hash[ha] = 1; //输出后标记为1
}
i++; //应输入文字串的下标后移一位
}
else if(a[i] >= '0'&&a[i] <= '9'){ //若为数字
int ha = a[i] - '0';
if(str_hash[ha] == 0){ //之前未输出过
printf("%c",a[i]);
str_hash[ha] = 1; //输出后标记为1
}
i++; //应输入文字串的下标后移一位
}
}
else{ //两文字串对应位置字符相同时,则下标同时后移一位
i++;
j++;
}
}
return 0;
}

将i++改至第18,30及38行的位置,将导致倒数第二个测试点超时,因为一旦坏键为_且已输出,再次遇到时将不能进入判断条件内部,从而导致i不能得到更新,陷入死循环。

代码示例(C/C++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <cstdio>
#define MAXN 81
using namespace std;
int main()
{
char a[MAXN],b[MAXN]; //a[]为应该输入的文字,b[]为实际输入的文字
int str_hash[36] = {0}; //通过散列的方式标记某一坏掉的键是否已输出
int flag = 1; //单独标记下划线是否已输出(若下划线为坏掉的键)
scanf("%s",a); //输入应该输入的文字
getchar(); //吸收掉换行
scanf("%s",b); //输入实际输入的文字
int i = 0,j = 0;
while(a[i] != '\0'){ //注意此处的条件
if(a[i] != b[j]){
if(flag&&a[i] == '_'){ //'_'为坏键且还未输出
printf("_");
flag = 0; //标记'_'已输出
}
else if((a[i] >= 'a'&&a[i] <= 'z')
||(a[i] >= 'A'&&a[i] <= 'Z')){ //小写或大写字母
if(a[i] >= 'a'&&a[i] <= 'z'){ //若为小写字母
a[i] -= 32; //转换成大写字母
}
int ha = a[i] - 55; //散列,'A'散列对应下标10
if(str_hash[ha] == 0){ //之前未输出过
printf("%c",a[i]);
str_hash[ha] = 1; //输出后标记为1
}
}
else if(a[i] >= '0'&&a[i] <= '9'){ //若为数字
int ha = a[i] - '0';
if(str_hash[ha] == 0){ //之前未输出过
printf("%c",a[i]);
str_hash[ha] = 1; //输出后标记为1
}
}
i++; //应输入文字串的下标后移一位
}
else{ //两文字串对应位置字符相同时,则下标同时后移一位
i++;
j++;
}
}
return 0;
}

题目来源:PAT乙级1029
作者:CHEN, Yue
单位:浙江大学

稀罕作者
Mengzhao Wang WeChat Pay

WeChat Pay

Mengzhao Wang Alipay

Alipay

# C/C++ # PAT # 编程
PAT乙级1028 || 人口普查(详解,C/C++示例,测试点分析)
PAT乙级1030 || 完美数列(详解,C/C++示例,测试点分析)
  • Table of Contents
  • Overview
Mengzhao Wang

Mengzhao Wang

Try? All the way !
122 posts
6 categories
21 tags
  1. 1. 旧键盘
    1. 1.1. 题目描述
    2. 1.2. 输入格式
    3. 1.3. 输出格式
    4. 1.4. 输入样例
    5. 1.5. 输出样例
    6. 1.6. 问题解决
      1. 1.6.1. 解题思想
      2. 1.6.2. 易错提醒
      3. 1.6.3. 代码示例(C/C++)
© 2021 Mengzhao Wang