1. PAT乙级1014题解:福尔摩斯的约会
这道题目考察字符串处理的基本功,需要从两对字符串中提取隐藏的约会信息。题目看似简单,但实际编码时容易在细节上翻车。下面我将详细解析解题思路和实现细节。
1.1 题目核心需求分析
题目要求从四行输入中提取三个关键信息:
- 星期几(第1对字符串中第1个相同的大写字母,范围A-G)
- 小时(第1对字符串中第2个相同的字符,数字0-9或字母A-N)
- 分钟(第2对字符串中第1个相同字母的位置索引)
特别需要注意的是题目中的隐藏条件:
- 星期几的判断必须限定在A-G范围内,写成A-Z会扣分
- 小时部分需要区分数字和字母的不同处理方式
- 分钟是字母出现的位置,不是字符本身
1.2 解题思路拆解
我的解题思路分为三个主要步骤:
-
星期几判断:
- 遍历前两个字符串,找到第一个相同的大写字母
- 验证该字母必须在A-G范围内
- 使用字母与'A'的偏移量计算星期几
-
小时判断:
- 从星期几匹配位置之后继续查找
- 找到下一个相同的字符
- 区分数字(0-9)和字母(A-N)两种情况处理
-
分钟判断:
- 遍历后两个字符串
- 找到第一个相同的字母字符(不区分大小写)
- 记录该字母出现的位置索引
2. 代码实现详解
2.1 基础准备与输入处理
cpp复制#include<bits/stdc++.h>
using namespace std;
int main() {
string s1, s2, s3, s4;
getline(cin, s1);
getline(cin, s2);
getline(cin, s3);
getline(cin, s4);
// 星期映射表
string weekdays[8] = {"###", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
这里使用getline读取四行输入,避免使用cin可能遇到的空格截断问题。星期映射表从索引1开始,对应A-G的星期表示。
2.2 星期几的判断实现
cpp复制int num = 0;
for(int i = 0; i < min(s1.size(), s2.size()); i++) {
if(s1[i] == s2[i] && s1[i] >= 'A' && s1[i] <= 'G') {
cout << weekdays[s1[i] - 'A' + 1] << " ";
num = i;
break;
}
}
关键点说明:
- 使用
min(s1.size(), s2.size())防止数组越界 - 严格限定字母范围A-G('A'到'G'的ASCII码是65-71)
- 记录匹配位置
num供后续小时判断使用 - 通过
s1[i] - 'A' + 1计算星期索引(A对应1,即MON)
2.3 小时的判断实现
cpp复制for(int i = num + 1; i < min(s1.size(), s2.size()); i++) {
if(s1[i] == s2[i]) {
if(isdigit(s1[i])) {
printf("%02d:", s1[i] - '0');
break;
}
else if(s1[i] >= 'A' && s1[i] <= 'N') {
printf("%02d:", s1[i] - 'A' + 10);
break;
}
}
}
注意事项:
- 从星期几匹配的下一个位置开始查找(num+1)
- 数字情况(0-9):直接转换为数字
- 字母情况(A-N):A对应10,B对应11,依此类推
- 使用
%02d保证输出两位,不足补零
2.4 分钟的判断实现
cpp复制for(int i = 0; i < min(s3.size(), s4.size()); i++) {
if(s3[i] == s4[i] && isalpha(s3[i])) {
printf("%02d", i);
break;
}
}
关键细节:
- 使用
isalpha()判断是否为字母字符 - 输出匹配位置的索引值
- 同样使用
%02d格式化输出
3. 常见错误与调试技巧
3.1 易错点分析
-
星期几范围错误:
- 错误做法:写成A-Z
- 正确做法:必须限定A-G
- 后果:测试点2会出错,扣2分
-
小时判断逻辑错误:
- 未区分数字和字母情况
- 字母范围未限定A-N
- 数字未考虑前导零
-
分钟判断错误:
- 使用字符本身而非位置索引
- 未考虑大小写字母都有效
- 忘记使用
isalpha()判断
3.2 调试技巧
-
边界测试用例:
text复制
ABCDEFG ABADEFG abc abd预期输出:MON 01:00
-
极端情况测试:
text复制
AAAAAAAAAA AAAAAAAAAA zzzzzzzzzA zzzzzzzzzA预期输出:MON 00:09
-
使用调试打印:
在关键位置添加临时打印语句,如:cpp复制cout << "Debug: found match at " << i << ": " << s1[i] << endl;
4. 算法优化与扩展思考
4.1 代码优化建议
-
使用函数封装:
将三个判断逻辑封装成独立函数,提高代码可读性 -
提前计算字符串长度:
cpp复制int len1 = min(s1.size(), s2.size()); int len2 = min(s3.size(), s4.size());避免在循环中重复计算
-
统一字符处理:
使用toupper()统一处理大小写字母
4.2 类似题目推荐
- PAT乙级1009:说反话(字符串处理)
- PAT乙级1024:科学计数法(字符串解析)
- PAT甲级1136:A Delayed Palindrome(字符串操作)
5. 个人实现心得
在实际编码过程中,我最初也犯了星期几范围判断的错误。经过反复测试才发现题目隐藏的条件限制。这提醒我在处理字符串匹配问题时:
- 必须仔细阅读题目中的每一个字
- 特别注意大小写、范围等限制条件
- 边界情况要单独测试
另一个收获是isalpha()和isdigit()这两个函数的使用,它们比直接判断ASCII码范围更可靠和易读。例如:
cpp复制// 不如直接使用isalpha(c)
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
最后,格式化输出%02d在时间表示中非常实用,可以避免复杂的条件判断来补零。
