题目的主要信息:

  • 输入两串字符,第一个单词作为密匙,去除单词中的重复字符,再用字母表中剩余的字母填充完整。
  • 在对字符串进行加密时,用密钥中的字母一一取代原文的字母,需要保留字母的大小写状态。

方法一:

我们可以根据题意进行计算求解。用一个vector保存密钥,对遍历一遍输入的单词,将所有字母转换为小写字母,不保留重复的字符,然后在vector中加入26个字母中剩余的其他字母,这样就完成了密钥。需要注意的是,上面获得的密钥全部是小写字母。对字符串加密的时候,判断当前字母s[i]是大写还是小写,如果是小写字母,则直接通过ASCII码计算相对位置s[i]-'a',获得密钥中对应的字母;如果是大写字母,得到密钥中对应的字母后再转为大写字母。 alt

具体做法:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

int main(){
    string s1,s2;
    while(cin>>s1>>s2){//可能有多个输入
        vector<char> key;//密钥
        for(int i=0;i<s1.size();i++){
            if(s1[i]>='A'&&s1[i]<='Z'){//统一字母大小写
                s1[i]=s1[i]-'A'+'a';
            }
            auto iter=find(key.begin(),key.end(),s1[i]);
            if(iter==key.end()){//去除单词中的重复部分,存到密钥中
                key.push_back(s1[i]);
            }
        }
        for(char c='a';c<='z';c++){//将剩余的字母存到密钥中
            auto iter=find(key.begin(),key.end(),c);
            if(iter==key.end()){
                key.push_back(c);
            }
        }
        char result;
        //接下来对字符串进行加密
        for(int i=0;i<s2.size();i++){
            if(s2[i]>='a'&&s2[i]<='z'){//原字符是小写的
                result=key[s2[i]-'a'];
            }
            if(s2[i]>='A'&&s2[i]<='Z'){//原字符是大写的
                result=key[s2[i]-'a']-'a'+'A';//根据ASCII码转换为大写
            }
            cout<<result;
        }
        cout<<endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),需要遍历一遍字符串。
  • 空间复杂度:O(1)O(1)O(1),虽然使用了vector保存密钥,但是vector大小为26个字符,是常数空间大小。

方法二:

方法一是使用了find函数查找重复字母,我们也可以用一个数组count来统计每个字母出现的频数,这个方法不会增加算法的复杂度。遍历单词时,增加当前字母的频数,只有当频数为1时,说明该单词是首次出现的,需要存到密钥中。补充26个字母中剩余字母时,只要将那些频数为0的字母加入密钥。

具体做法:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

int main(){
    string s1,s2;
    while(cin>>s1>>s2){//可能有多个输入
        vector<char> key;//密钥
        int count[26]={0};//统计字母出现的次数
        for(int i=0;i<s1.size();i++){
            if(s1[i]>='A'&&s1[i]<='Z'){//统一字母大小写
                s1[i]=s1[i]-'A'+'a';
            }
            int p=s1[i]-'a';
            count[p]++;//计算字母出现的频数
            if(count[p]==1){//该字母第一次出现,把它加到密钥中
                key.push_back(s1[i]);
            }
        }
        for(char c='a';c<='z';c++){//将剩余的字母存到密钥中
            int p=c-'a';
            if(count[p]==0){//该字母没有出现过,把它加到密钥中
                key.push_back(c);
            }
        }
        char result;
        //接下来对字符串进行加密
        for(int i=0;i<s2.size();i++){
            if(s2[i]>='a'&&s2[i]<='z'){//原字符是小写的
                result=key[s2[i]-'a'];
            }
            if(s2[i]>='A'&&s2[i]<='Z'){//原字符是大写的
                result=key[s2[i]-'a']-'a'+'A';//根据ASCII码转换为大写
            }
            cout<<result;
        }
        cout<<endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n),需要遍历一遍字符串。
  • 空间复杂度:O(1)O(1)O(1),虽然使用了vector保存密钥,和count数组统计字母出现的频数,但是vector和count大小为26个字符,是常数空间大小。