相关知识
- 选择语句有哪些排列组合方式?——优先使用级联,合理使用开关,避免过度嵌套,谨慎使用串联。
级联(互斥):使用相关的if-else-if结构,按顺序检查条件,只会执行第一个符合条件的分支。开关(离散值):使用switch和case和break和default,基于单个表达式的值进行多路分支。嵌套(层次):if语句中包含if语句,是最复杂最不容易理清逻辑的方式,谨慎使用。本题第一轮第五版就用了嵌套,但是可读性并不如第二轮第二版的级联。串联(独立):多个独立的if语句依次排列,每个条件都会判断,可能执行多个分支。本题第二轮第一版就错在把串联当级联用了。
第一轮
第一版(0/21)
#include <iostream>
using namespace std;
string process1(string& a) {
for (char c : a) {
if ((c >= 'a' && c < 'z') || (c >= 'A' && c < 'Z')) {
c = c + 1;
} else if (c == 'z') {
c = 'A';
} else if (c == 'Z') {
c = 'a';
} else if (c >= '0' && c < '9') {
c = c + 1;
} else if (c == '9') {
c = '0';
}
}
return a;
}
string process2(string& b) {
for (char c : b) {
if ((c <= 'z' && c > 'a') || (c <= 'Z' && c > 'z')) {
c = c - 1;
} else if (c == 'A') {
c = 'z';
} else if (c == 'a') {
c = 'Z';
} else if (c <= '9' && c > '0') {
c = c - 1;
} else if (c == '0') {
c = '9';
}
}
return b;
}
int main() {
string s, t;
cin >> s;
cin >> t;
cout << process1(s) << endl;
cout << process2(t) << endl;
}
// 64 位输出请用 printf("%lld")
- 所有用例都没通过,第一怀疑是不符合题意,重读一遍题目发现没有做好大小写转换。
- 另外这个条件也写错了——
(c <= 'Z' && c > 'z')。
第二版(0/21)
#include <cctype>
#include <iostream>
using namespace std;
string process1(string& a) {
for (char c : a) {
if (c >= 'a' && c < 'z') {
c = toupper(c + 1);
} else if (c >= 'A' && c < 'Z') {
c = tolower(c + 1);
} else if (c == 'z') {
c = 'A';
} else if (c == 'Z') {
c = 'a';
} else if (c >= '0' && c < '9') {
c = c + 1;
} else if (c == '9') {
c = '0';
}
}
return a;
}
string process2(string& b) {
for (char c : b) {
if (c <= 'z' && c > 'a') {
c = toupper(c) - 1;
} else if (c <= 'Z' && c > 'A') {
c = tolower(c) - 1;
} else if (c == 'A') {
c = 'z';
} else if (c == 'a') {
c = 'Z';
} else if (c <= '9' && c > '0') {
c = c - 1;
} else if (c == '0') {
c = '9';
}
}
return b;
}
int main() {
string s, t;
cin >> s;
cin >> t;
cout << process1(s) << endl;
cout << process2(t) << endl;
}
// 64 位输出请用 printf("%lld")
- 从代码逻辑上看,找不着问题。
- 智能反馈:
for (char c : a)里,c是副本,对c的修改是无效的。
第三版(AC)
#include <cctype>
#include <iostream>
using namespace std;
string process1(string& s) {
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a' && s[i] < 'z') {
s[i] = toupper(s[i] + 1);
} else if (s[i] >= 'A' && s[i] < 'Z') {
s[i] = tolower(s[i] + 1);
} else if (s[i] == 'z') {
s[i] = 'A';
} else if (s[i] == 'Z') {
s[i] = 'a';
} else if (s[i] >= '0' && s[i] < '9') {
s[i] = s[i] + 1;
} else if (s[i] == '9') {
s[i] = '0';
}
}
return s;
}
string process2(string& s) {
for (int i = 0; i < s.size(); i++) {
if (s[i] <= 'z' && s[i] > 'a') {
s[i] = toupper(s[i]) - 1;
} else if (s[i] <= 'Z' && s[i] > 'A') {
s[i] = tolower(s[i]) - 1;
} else if (s[i] == 'A') {
s[i] = 'z';
} else if (s[i] == 'a') {
s[i] = 'Z';
} else if (s[i] <= '9' && s[i] > '0') {
s[i] = s[i] - 1;
} else if (s[i] == '0') {
s[i] = '9';
}
}
return s;
}
int main() {
string s, t;
cin >> s;
cin >> t;
cout << process1(s) << endl;
cout << process2(t) << endl;
}
// 64 位输出请用 printf("%lld")
- 这个版本的代码修复了「修改副本因而无效」的问题——使用索引访问并修改字符串中的字符,而不是修改局部变量。
- 这个版本的代码存在不够简洁的问题,比如对字母和数字的判断。
第四版(优化但有错,5/21)
#include <cctype>
#include <iostream>
using namespace std;
string process1(string s) {
for (int i = 0; i < s.size(); i++) {
if (islower(s[i])) {
if (s[i] == 'z') s[i] = 'A';
else s[i] = toupper(s[i] + 1);
} else if (isupper(s[i])) {
if (s[i] == 'Z') s[i] = 'a';
s[i] = tolower(s[i] + 1);
} else if (isdigit(s[i])) {
if (s[i] == '9') s[i] = '0';
else s[i] = s[i] + 1;
}
}
return s;
}
string process2(string s) {
for (int i = 0; i < s.size(); i++) {
if (isupper(s[i])) {
if (s[i] == 'A') s[i] = 'z';
else s[i] = tolower(s[i]) - 1;
} else if (islower(s[i])) {
if (s[i] == 'a') s[i] = 'Z';
s[i] = toupper(s[i]) - 1;
} else if (isdigit(s[i])) {
if (s[i] == '0') s[i] = '9';
else s[i] = s[i] - 1;
}
}
return s;
}
int main() {
string s, t;
cin >> s;
cin >> t;
cout << process1(s) << endl;
cout << process2(t) << endl;
}
// 64 位输出请用 printf("%lld")
- 这个版本重新梳理了分支结构,顺便通过引用函数简化了判断逻辑。
- 这个版本还将参数改为值传递而不是引用传递,避免修改原始字符串。
- 这里发生了报错,检查后发现是漏写了两个
else。
第五版(优化且AC)
#include <cctype>
#include <iostream>
using namespace std;
string encrypt(string s) {
for (int i = 0; i < s.size(); i++) {
if (islower(s[i])) {
if (s[i] == 'z') s[i] = 'A';
else s[i] = toupper(s[i] + 1);
} else if (isupper(s[i])) {
if (s[i] == 'Z') s[i] = 'a';
else s[i] = tolower(s[i] + 1);
} else if (isdigit(s[i])) {
if (s[i] == '9') s[i] = '0';
else s[i] = s[i] + 1;
}
}
return s;
}
string decrypt(string s) {
for (int i = 0; i < s.size(); i++) {
if (isupper(s[i])) {
if (s[i] == 'A') s[i] = 'z';
else s[i] = tolower(s[i]) - 1;
} else if (islower(s[i])) {
if (s[i] == 'a') s[i] = 'Z';
else s[i] = toupper(s[i]) - 1;
} else if (isdigit(s[i])) {
if (s[i] == '0') s[i] = '9';
else s[i] = s[i] - 1;
}
}
return s;
}
int main() {
string s, t;
cin >> s;
cin >> t;
cout << encrypt(s) << endl;
cout << decrypt(t) << endl;
}
// 64 位输出请用 printf("%lld")
- 修复了第四版的错误,顺带优化了函数的名字。
第二轮
第一版(0/21)
#include <cctype>
#include <iostream>
using namespace std;
string encrypt(const string& a) {
string s = a;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a' && s[i] < 'z') s[i] = toupper(s[i] + 1);
if (s[i] >= 'A' && s[i] < 'Z') s[i] = tolower(s[i] + 1);
if (s[i] >= '0' && s[i] < '9') s[i] = s[i] + 1;
if (s[i] == 'z') s[i] = 'A';
if (s[i] == 'Z') s[i] = 'a';
if (s[i] == '9') s[i] = '0';
}
return s;
}
string decrypt(const string& b) {
string s = b;
for (int i = 0; i < s.size(); i++) {
if (s[i] > 'a' && s[i] <= 'z') s[i] = toupper(s[i] - 1);
if (s[i] > 'A' && s[i] <= 'Z') s[i] = tolower(s[i] - 1);
if (s[i] > '0' && s[i] <= '9') s[i] = s[i] - 1;
if (s[i] == 'a') s[i] = 'Z';
if (s[i] == 'A') s[i] = 'z';
if (s[i] == '0') s[i] = '9';
}
return s;
}
int main() {
string s;
cin >> s;
string t;
cin >> t;
cout << encrypt(s) << endl;
cout << decrypt(t) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
- 注意这一版又不自觉使用了范围for循环修改字符副本,导致修改无效。此外传进来的字符串和之前的版本不一样,用了
const,这就导致不能直接修改,必须在函数体里面声明一个临时变量拿来修改。 - 这一版犯了个很大的错误,即认为选择语句应该串联,实际上应该级联。否则前面的语句执行完毕后,修改后的字符可能会触发后面的选择语句,而实际上我们要的是执行一个就别执行了。
第二版(AC)
#include <cctype>
#include <iostream>
using namespace std;
string encrypt(const string& a) {
string s = a;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a' && s[i] < 'z') s[i] = toupper(s[i] + 1);
else if (s[i] >= 'A' && s[i] < 'Z') s[i] = tolower(s[i] + 1);
else if (s[i] >= '0' && s[i] < '9') s[i] = s[i] + 1;
else if (s[i] == 'z') s[i] = 'A';
else if (s[i] == 'Z') s[i] = 'a';
else if (s[i] == '9') s[i] = '0';
}
return s;
}
string decrypt(const string& b) {
string s = b;
for (int i = 0; i < s.size(); i++) {
if (s[i] > 'a' && s[i] <= 'z') s[i] = toupper(s[i] - 1);
else if (s[i] > 'A' && s[i] <= 'Z') s[i] = tolower(s[i] - 1);
else if (s[i] > '0' && s[i] <= '9') s[i] = s[i] - 1;
else if (s[i] == 'a') s[i] = 'Z';
else if (s[i] == 'A') s[i] = 'z';
else if (s[i] == '0') s[i] = '9';
}
return s;
}
int main() {
string s;
cin >> s;
string t;
cin >> t;
cout << encrypt(s) << endl;
cout << decrypt(t) << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
- 将串联的选择语句改为级联,果然通过了。