题目的主要信息:
-
加密方法为:
当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写;
当内容是数字时则把该数字加1;
其他字符不做变化。
-
解密方法为加密的逆过程
-
求第一个字符串的加密和第二个字符串的解密
方法一:直接比较替换
具体做法:
加密的时候遍历需要加密的字符串,检查每个字符,如果是大写字母,我们用ASCⅡ码将其转变成数字(即该字母在26字母表中的序号,0开始),然后加1对26取模,然后再加上小写字母a的ASCⅡ码即转换成功;如果是小写字母与大写字母类似,但是后续加上大写字母的A即可。如果是数字字符,我们用ASCⅡ码将其转变成对应的数字(即该字符在0-9中的序号,0开始),然后加1对10取模,然后再加上字符0的ASCⅡ码即转换成功。如果三种都不是,那么就是其他字符,不用变。
解密过程是加密的逆过程,大小写转换还是需要的,但是变成了字母数字向前一位,为了防止减1取模26以后或10以后变成负数,我们直接在后面加上26或者10以后再对26或者10取模就行了。
#include<iostream>
#include<string>
using namespace std;
void encrypt(string& str){ //加密函数
for(int i = 0; i < str.length(); i++){
if(str[i] >= 'a' && str[i] <= 'z'){ //小写转大写且后移一位字母
str[i] = (str[i] - 'a' + 1) % 26 + 'A';
}else if(str[i] >= 'A' && str[i] <= 'Z'){ //大写转小写且后移一位字母
str[i] = (str[i] - 'A' + 1) % 26 + 'a';
}else if(str[i] >= '0' && str[i] <= '9'){ //数字后移
str[i] = (str[i] - '0' + 1) % 10 + '0';
}
}
}
void decrypt(string& str){ //解密函数
for(int i = 0; i < str.length(); i++){
if(str[i] >= 'a' && str[i] <= 'z'){ //小写转大写且前移一位字母
str[i] = (str[i] - 'a' - 1 + 26) % 26 + 'A';
}else if(str[i] >= 'A' && str[i] <= 'Z'){ //大写转小写且前移一位字母
str[i] = (str[i] - 'A' - 1 + 26) % 26 + 'a';
}else if(str[i] >= '0' && str[i] <= '9'){ //数字前移
str[i] = (str[i] - '0' - 1 + 10) % 10 + '0';
}
}
}
int main(){
string str1, str2;
while(cin >> str1 >> str2){ //读入两个字符串
encrypt(str1);
decrypt(str2);
cout << str1 << endl << str2 << endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:,其中为较长字符串的长度,两个字符串都遍历一次,取较大值为复杂度
- 空间复杂度:,两个字符串属于必要空间,无额外空间
方法二:索引查表
具体做法: 我们可以用一个的数组把所有的字母数字的转变都对应起来,第0行是加密前的字符,第1行是加密后的字符,每一列都一一对应,这样我们每次只要找到字符再数组中的位置就可以转换了。
怎么找位置,我们还可以用一个索引。我们都知道字符的ASCⅡ码与数字一一对应,其中数字字母最大的对应122,我们可以准备一个123大小的数组,初始置为-1,这样字符就会与下标一一对应,那么我们通过字符可以直接访问数组中的元素,那我们数组中就记录该字母在上表中所在的下标,准备两个这样的索引数组,加密记录第0维的下标,解密记录第1维的下标,这样我们遍历字符串的时候就可以通过数组直接访问转换表的下标,通过下标找到另一维的值就是它要转换的值,而其他字符没有没有准备下标,就都是初始值-1。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//加密与解密过程字符的对应表
char table[2][62] = {{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9'},
{'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','a','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','1','2','3','4','5','6','7','8','9','0'}
};
vector<int> en_index(123, -1); //相应字符在table[0]中的下标
vector<int> de_index(123, -1); //相应字符在table[1]中的下标
void encrypt(string& str){ //加密函数
for(int i = 0; i < str.length(); i++){
if(en_index[str[i]] != -1){ //不等于-1代表字母或者数字
str[i] = table[1][en_index[str[i]]];
}
}
}
void decrypt(string& str){ //解密函数
for(int i = 0; i < str.length(); i++){
if(de_index[str[i]] != -1){ //不等于-1代表字母或者数字
str[i] = table[0][de_index[str[i]]];
}
}
}
int main(){
string str1, str2;
for(int i = 0; i < 62; i++){ //遍历table的两维,将下标加入字母对应的索引
en_index[table[0][i]] = i;
de_index[table[1][i]] = i;
}
while(cin >> str1 >> str2){
encrypt(str1);
decrypt(str2);
cout << str1 << endl << str2 << endl;
}
return 0;
}
复杂度分析:
- 时间复杂度:,其中为较长字符串的长度,两个字符串都遍历一次,取较大值为复杂度,处理下标遍历常数次
- 空间复杂度:,两个字符串属于必要空间,其他辅助空间看起来大,但都是常数大小