相关知识

  1. 选择语句有哪些排列组合方式?——优先使用级联,合理使用开关,避免过度嵌套,谨慎使用串联。 级联(互斥):使用相关的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")

  1. 所有用例都没通过,第一怀疑是不符合题意,重读一遍题目发现没有做好大小写转换。
  2. 另外这个条件也写错了——(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")

  1. 从代码逻辑上看,找不着问题。
  2. 智能反馈: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")

  1. 这个版本的代码修复了「修改副本因而无效」的问题——使用索引访问并修改字符串中的字符,而不是修改局部变量。
  2. 这个版本的代码存在不够简洁的问题,比如对字母和数字的判断。

第四版(优化但有错,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")

  1. 这个版本重新梳理了分支结构,顺便通过引用函数简化了判断逻辑。
  2. 这个版本还将参数改为值传递而不是引用传递,避免修改原始字符串。
  3. 这里发生了报错,检查后发现是漏写了两个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")

  1. 修复了第四版的错误,顺带优化了函数的名字。

第二轮

第一版(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")

  1. 注意这一版又不自觉使用了范围for循环修改字符副本,导致修改无效。此外传进来的字符串和之前的版本不一样,用了const,这就导致不能直接修改,必须在函数体里面声明一个临时变量拿来修改。
  2. 这一版犯了个很大的错误,即认为选择语句应该串联,实际上应该级联。否则前面的语句执行完毕后,修改后的字符可能会触发后面的选择语句,而实际上我们要的是执行一个就别执行了。

第二版(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")

  1. 将串联的选择语句改为级联,果然通过了。