第一次看到PAT乙级1118题时,很多人会被题目中"如需挪车请致电"这样的中文提示吸引注意力,却忽略了题干中更关键的技术细节——"每个计算至多只有1个运算符"。这个看似简单的限制条件,恰恰是测试点4的考察重点,也是大多数考生容易翻车的地方。
在实际考试中,我见过太多同学花费大量时间处理复杂的中英文数字转换,却在最基本的运算符处理上栽了跟头。比如有考生写出了能处理"3+5-2"这样多运算符表达式的代码,却因为没注意到题目限制而丢分。这就像准备了一桌满汉全席,结果客人只要一碗清汤面——过度设计反而成了扣分点。
题目明确给出了三个关键约束:
最后这个限制才是真正的考点。很多同学在练习时养成了处理复杂表达式的习惯,看到"3+5"就下意识想到后面可能有"-2*4",于是写出了能处理多运算符的代码。这在平时练习是好事,但在本题中反而会导致逻辑复杂化,甚至引入不必要的错误。
测试点4专门考察对单运算符限制的处理。常见错误包括:
这些"过度设计"不仅浪费时间,还可能因为逻辑复杂化引入新的bug。正确的做法是相信题目给出的保证,直接按单运算符场景处理。
首先需要建立中文数字与阿拉伯数字的映射关系。使用map容器是最直观的选择:
cpp复制string s[10] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
map<string, int> mp;
for (int i = 0; i < 10; ++i) {
mp[s[i]] = i;
}
这个映射表将帮助我们在处理中文数字输入时快速转换为对应的数值。注意"ling"到"jiu"的拼写要准确,这是处理中文数字的基础。
核心处理逻辑需要区分三种输入情况:
cpp复制for (int i = 0; i < 11; ++i) {
string ss;
cin >> ss;
if (isdigit(ss[0])) { // 阿拉伯数字情况
// 处理数字与运算符
} else if (ss.substr(0, 4) == "sqrt") { // 开方运算
int r = stoi(ss.substr(4));
cout << sqrt(r);
} else { // 中文数字情况
cout << mp[ss];
}
}
对于阿拉伯数字开头的输入,我们需要扫描字符串寻找运算符。由于题目保证最多一个运算符,找到后就可以立即处理,不需要考虑后续可能存在的其他运算符。
当检测到阿拉伯数字输入时,遍历字符串寻找运算符位置:
cpp复制int tag = 0;
for (int j = 0; j < ss.length(); ++j) {
if (!isdigit(ss[j])) {
tag = 1;
// 提取运算符前后的数字
int num1 = stoi(ss.substr(0, j));
int num2 = stoi(ss.substr(j + 1));
// 根据运算符类型计算结果
switch (ss[j]) {
case '+': cout << num1 + num2; break;
case '-': cout << num1 - num2; break;
case '*': cout << num1 * num2; break;
case '/': cout << num1 / num2; break;
case '%': cout << num1 % num2; break;
case '^': cout << pow(num1, num2); break;
}
break; // 找到第一个运算符后即可退出
}
}
if (tag == 0) cout << ss; // 无运算符情况
关键点在于找到第一个运算符后立即处理并退出循环,这正是利用题目"至多一个运算符"的保证。如果没有这个保证,我们就需要继续扫描整个字符串。
题目中除了基本运算,还涉及sqrt和幂运算(^)。sqrt的处理相对特殊,因为它不是中缀运算符:
cpp复制if (ss.substr(0, 4) == "sqrt") {
int r = stoi(ss.substr(4));
cout << sqrt(r);
}
这里需要注意sqrt后面紧跟的数字可能有多位,使用stoi可以自动处理这种情况。同样,由于题目保证表达式的简单性,我们不需要考虑像"sqrt(2+3)"这样的复杂表达式。
虽然题目保证了表达式的简单性,但仍需测试一些边界情况:
在解决这类题目时,我通常会:
例如,可以在运算符处理前添加调试输出:
cpp复制cout << "Debug: " << ss.substr(0, j) << " " << ss[j] << " " << ss.substr(j+1) << endl;
这样可以帮助快速定位问题所在。记住在提交代码前删除这些调试输出。
这道题教会我们几个重要的编程原则:
在实际编程中,这种"按需设计"的思维非常重要。过度工程化不仅增加开发成本,还可能引入不必要的复杂性。这道题正是考察开发者能否准确理解需求并给出恰到好处的解决方案。