菜鸡的C/C++复健之路——PAT刷题篇
–此贴只是个人刷PAT的记录与总结,不用做任何商业用途,转载请告知–
PAT 乙级 1014福尔摩斯的约会
大侦探福尔摩斯接到一张奇怪的字条:我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm
。大侦探很快就明白了,字条上奇怪的乱码实际上就是约会的时间星期四 14:04
,因为前面两字符串中第 1 对相同的大写英文字母(大小写有区分)是第 4 个字母 D
,代表星期四;第 2 对相同的字符是 E
,那是第 5 个英文字母,代表一天里的第 14 个钟头(于是一天的 0 点到 23 点由数字 0 到 9、以及大写字母 A
到 N
表示);后面两字符串第 1 对相同的英文字母 s
出现在第 4 个位置(从 0 开始计数)上,代表第 4 分钟。现给定两对字符串,请帮助福尔摩斯解码得到约会的时间。
输入格式:
输入在 4 行中分别给出 4 个非空、不包含空格、且长度不超过 60 的字符串。
输出格式:
在一行中输出约会的时间,格式为 DAY HH:MM
,其中 DAY
是某星期的 3 字符缩写,即 MON
表示星期一,TUE
表示星期二,WED
表示星期三,THU
表示星期四,FRI
表示星期五,SAT
表示星期六,SUN
表示星期日。题目输入保证每个测试存在唯一解。
输入样例: 输出样例:
3485djDkxh4hhGE THU 14:04
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm
思路:
利用ASCII码进行字符的比较,对两个字符串进行循环比较,利用空的容器re去存储比较结果。
int main() {
string m,n,m1,n1,re;
cin >> m >> n >> m1 >> n1;
char temp;
int i, j, ln, lm;
if (m.size() > n.size()) {
re = m; m = n; n = re;
re.clear();
}
//有这一步是因为双循环的外层循环是以字符串长度小的一方为参考写的,如果换做大的为参考会报错。
lm = m.size();
ln = n.size();
int flag = lm;
for (i = 0; i<lm; ++i) {
temp = m[i];
for (j = 0; j < ln; ++j){
//等同于if (temp == n[j] && temp >= 'A' && temp <= 'G' && re.size() < 1)
if (temp == n[j] && temp >= 65 && temp <= 90 && re.size() < 1){
re.push_back(temp);
flag = j;//此处将flag赋值用以进入下面的循环
break;
}//已经得到第一个相同的大写字母了,要跳出这层循环
}
for (;(ln--)!=flag && i>flag;){//从第一个相同字母之后的位置开始下一个循环比较
if (temp == n[flag+1])
re.push_back(temp);
++flag;
}
}
进行的第三和第四个字符串比较时,发现题目中“后面两字符串第 1 对相同的英文字母 s 出现在第 4 个位置
”也就是说两个字符串不论长短,只要对比相同位置是否一致就可。类比第一和第二这两个字符串,似乎也符合。。。。。(题目如果只说找到相同元素,就不能只考虑对比相同位置)既然这样就可以将第一部分简化。
for (int i = 0, flag = 0; i < m.size(); ++i) {
if (!flag && m[i] == n[i] && m[i] >= 65 && m[i] <= 90 ){
re.push_back(m[i]);
flag = 1; //此处i可能还会是0,故不能写成flag = i;
}
else if (flag && m[i]== n[i])
re.push_back(m[i]);
}
同样的思路,写出第二部分:
for (int t = 0; t < m1.size(); ++t){
if (m1[t] == n1[t]) {
if ((m1[t] >= 97 && m1[t] <= 122) || (m1[t] >= 65 && m1[t] <= 90))
re.push_back(t+'0');//将int->char
}
}
第三部分是按题目要求输出,这一部分将re中的元素按个数出并处理为题目要求形式。
int temp;
if (re[1] >= 65)
temp = (int)(re[1] - 'A') + 10;
else
temp = (int)re[1];
if ((re[2] - '0') < 9)
cout << A[re[0] - 'A'] << ' ' << temp << ':' << 0 << re[2];
else
cout << A[re[0] - 'A'] << ' ' << temp << ':' << re[2];
return 0;
}
其实因为C++引入了输入流、输出流可以不另外用一个空容器去储存待输出数据,而是直接将待输出数据推入输出流即可。改变化简后的完整代码:
int main() {
string m, n, ml, nl;
string A[] = { "MON","TUE","WED","THU","FRI","SAT","SUN" };
cin >> m >> n >> ml >> nl;
int flag = 0;
for (int i = 0; i < m.size(); ++i){
if (!flag && m[i] == n[i] && m[i] >= 'A' && m[i] <= 'G'){
cout << A[m[i] - 'A'] << ' ';
flag = 1;
}
else if (flag && m[i] == n[i]){
if (m[i] >= 'A' && m[i] <= 'N'){
cout << m[i] - 'A' + 10 << ':';
break;//此处防止将第三个、第四个....相同的元素输出
}
else if (m[i] >= '0' && m[i] <= '9'){
cout << '0' << m[i] << ':';//根据题目要求单数值要补0
break;
}
}
}
for (int t = 0; t < ml.size(); ++t){
if (ml[t] == nl[t]){
if ((ml[t] >= 'a' && ml[t] <= 'z') || (ml[t] >= 'A' && ml[t] <= 'Z')){
if (t < 10)
cout << '0' << t;//根据题目要求单数值要补0
else
cout << t;
}
}
}
return 0;
}
总结此题需要避免的几个坑:
1.第一个相同字符必须是大写字母,且必须在’A’ ~ ‘G’ 之间。(如果是A~Z,就有部分错误过不去)
2.第二个相同字符必须在’A’ ~ ‘N’ 或 ‘0’ ~ '9’之间 (道理同上)
3.第三个相同字符必须是字母。
值得学习的方法:
1. temp >= 65 && temp <= 90 直接写成 temp >= 'A' && temp <= 'G'
2. 用输出流去输出一串数据,省去存储待输出数据的容器。