题目的主要信息:

  • 给字符串加密,输入多个明文字符串,长度不超过100,输出多次密文
  • 加密方式:数字不变,对于小写字母abc--2, def--3, ghi--4, jkl--5, mno--6, pqrs--7, tuv--8 wxyz--9,对于大写字母变成小写字母再后移一位(z后移是a),其他字符也不变
  • 密码中没有空格

方法一:多次判断法

具体做法:

对于大写字母,我们利用加1取余的方式,加上ASCⅡ码的数字来变换,比如当前字符减去'A'就带着它是26个字母中的第几个(下标0开始),右移一位即加1,对26取模即循环,最后加上'a'转化为小写字母。

对于数字我们不变。

对于小写字母,利用switch-case对其分类讨论,转化为相应的数字即可。

因此,从明文到密文,我们遍历字符串依次进行上述操作即可,注意大写转出来的小写字母不用再转成数字。

#include<iostream>
#include<string>
using namespace std;

int main(){
    string s;
    while(cin >> s){
        for(int i = 0; i < s.length(); i++){
            if(s[i] >= 'A' && s[i] <= 'Z'){ //大写字母
                s[i] = (s[i] -'A' + 1) % 26 + 'a'; //后移一位,变成小写
                continue;
            }
            else if(s[i] >= '0' && s[i] <= '9') //数字不变
                continue;
            else{ //小写字母开始转换
                switch(s[i]){
                    case ('a'): case ('b'):  case ('c'): 
                        s[i] = '2';  break;
                    case ('d'): case ('e'):  case ('f'): 
                        s[i] = '3';  break;
                    case ('g'): case ('h'):  case ('i'): 
                        s[i] = '4';  break;
                    case ('j'): case ('k'):  case ('l'): 
                        s[i] = '5';  break;
                    case ('m'): case ('n'):  case ('o'): 
                        s[i] = '6';  break;
                    case ('p'): case ('q'):  case ('r'): case ('s'): 
                        s[i] = '7';  break;
                    case ('u'): case ('v'):  case ('t'): 
                        s[i] = '8';  break;
                    case ('w'): case ('x'):  case ('y'): case ('z'): 
                        s[i] = '9';  break;
                }
            }
        }
        cout << s << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n)nn为字符串长度,遍历一次字符串
  • 空间复杂度:O(1)O(1),无额外空间

方法二:打表

具体做法:

我们可以对26个字母用26个数组元素来代替,每个数组元素下标对应26个字母的位数,元素就是其转化成的数字。我们小写字母转数字直接查表然后加上'0'即可。

alt

#include<iostream>
#include<string>
using namespace std;

int main(){
    string s;
    int a[26] = {2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9};
    while(cin >> s){
        for(int i = 0; i < s.length(); i++){
            if(s[i] >= 'A' && s[i] <= 'Z'){ //大写字母
                s[i] = (s[i] -'A' + 1) % 26 + 'a'; //后移一位,变成小写
                continue;
            }
            else if(s[i] >= '0' && s[i] <= '9') //数字不变
                continue;
            else if(s[i] >= 'a' && s[i] <= 'z'){ //小写字母开始转换
                s[i] = a[s[i] - 'a'] + '0'; 
            }
        }
        cout << s << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n)nn为字符串的长度,一次遍历
  • 空间复杂度:O(1)O(1),常数级空间

方法三:正则表达式

具体做法:

我们还可以用正则表达式替换,首先依次替换字符串中的小写字母到相应的数字,然后转化大小字母为小写:先转化A-Y,通过ASCⅡ码加33即可,然后单独转换大写字母Z到小写字母a。

import re

while True:
    try:
        s = input().strip()
        passwd = re.sub("[a-c]", "2", s)
        passwd = re.sub("[d-f]", "3", passwd)
        passwd = re.sub("[g-i]", "4", passwd)
        passwd = re.sub("[j-l]", "5", passwd)
        passwd = re.sub("[m-o]", "6", passwd)
        passwd = re.sub("[p-s]", "7", passwd)
        passwd = re.sub("[t-v]", "8", passwd)
        passwd = re.sub("[w-z]", "9", passwd)

        def high_low(matched):  #从大写到小写
            str_up = matched.group(0)
            asc = ord(str_up) + 33 #ASCⅡ码差距33
            value = chr(asc)
            return str(value)

        passwd = re.sub("[A-Y]", high_low, passwd)
        passwd = re.sub("[Z]", "a", passwd) #替换Z

        print(str(passwd))
    except:
        break

复杂度分析:

  • 时间复杂度:O(n)O(n),正则表达式替换复杂度都是O(n)O(n)
  • 空间复杂度:O(1)O(1),常数级空间