题意

给定字符串加密方法,和多行字符串

要求对“一行字符串加密,一行字符串解密”的输出每一行

加密规则:

数字字符循环右移

字母字符循环右移并改变大小转换

方法

利用ASCII和数学得到解密函数

先考虑加密

注意到,数字,小写字母,大写字母,分别在ASCII上连续,同时C++中的char直接参与加减运算时,会以其ascii的值为准

alt

alt

alt

那么我们可以利用这个性质,分别对数字,小写字母,大写字母,编写转换逻辑


对于解密

考虑数字:右移10位会得到本身,现在密文是右移了1位,所以只要再右移9位就能得到原文

考虑字母:(不考虑大小写的情况)右移26位会得到本身,现在是右移了一位,所以只要再右移25位就能得到原文

综上我们有了加密和解密的算法,实现即可。

代码

#include<bits/stdc++.h>
using namespace std;

char echar(char ch){ // 加密
    if('0' <= ch && ch<= '9'){ // 数字
        return (ch-'0'+1)%10+'0';
    }
    if('a' <= ch && ch<= 'z'){ // 小写字母
        return (ch-'a'+1)%26+'A';
    }
    if('A' <= ch && ch<= 'Z'){ // 大写字母
        return (ch-'A'+1)%26+'a';
    }
    return ch;
}

char dchar(char ch){ // 解密
    if('0' <= ch && ch<= '9'){
        return (ch-'0'+9)%10+'0';
    }
    if('a' <= ch && ch<= 'z'){
        return (ch-'a'+25)%26+'A';
    }
    if('A' <= ch && ch<= 'Z'){
        return (ch-'A'+25)%26+'a';
    }
    return ch;
}

int main(){
    string s;
    while(getline(cin,s)){ // 读入
        for(auto ch:s){ // 加密行
            printf("%c",echar(ch));
        }
        printf("\n");
        getline(cin,s);
        for(auto ch:s){ // 解密行
            printf("%c",dchar(ch));
        }
        printf("\n");
    }
    return 0;
}

复杂度分析

时间复杂度: 我们读入所有字符,转换所有字符,转换的复杂度为常数,所以总时间复杂度为O(si)O(\sum |s_i|)

空间复杂度: 主要消耗在读入字符串,所以空间复杂度为O(max(si))O(max(|s_i|))

暴力解密

假设我们找不到解密的直接的逆函数。

那么我们至少知道,如果加密改变过字符,原字符是在数字和字母中的某一个

那么我们每次解密,可以枚举所有字母和数字,如果一个字母或数字的加密结果和密文相等,则找到原文

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = (a);i<=b;i++)

char echar(char ch){ // 只有加密函数
    if('0' <= ch && ch<= '9'){
        return (ch-'0'+1)%10+'0';
    }
    if('a' <= ch && ch<= 'z'){
        return (ch-'a'+1)%26+'A';
    }
    if('A' <= ch && ch<= 'Z'){
        return (ch-'A'+1)%26+'a';
    }
    return ch;
}

int main(){
    string s;
    while(getline(cin,s)){
        for(auto ch:s){
            printf("%c",echar(ch));
        }
        printf("\n");
        getline(cin,s);
        for(auto ch:s){ // 解密
            bool found = false;
            rep(orich,'0','z'+1){ // 遍历所有字母数字
                if(echar(orich) == ch){ // 枚举找原文
                    printf("%c",char(orich));
                    found = true;
                    break;
                }
            }
            if(!found){
                printf("%c",ch);
            }
        }
        printf("\n");
    }
    return 0;
}

复杂度分析

时间复杂度: 对于加密部分,每个字符是常数时间的处理代价。对于解密部分,虽然现在不是直接解密出字符,但是因为枚举的数量是常数个,所以依然是常数的时间代价,所以总时间复杂度为O(si)O(\sum |s_i|)

空间复杂度: 主要消耗在读入字符串,所以空间复杂度为O(max(si))O(max(|s_i|))