【算法题解】简单密码

264 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情 

描述

现在有一种密码变换算法。

九键手机键盘上的数字与字母的对应: 1--1, abc--2, def--3, ghi--4, jkl--5, mno--6, pqrs--7, tuv--8 wxyz--9, 0--0,把密码中出现的小写字母都变成九键键盘对应的数字,如:a 变成 2,x 变成 9.

而密码中出现的大写字母则变成小写之后往后移一位,如:X ,先变成小写,再往后移一位,变成了 y ,例外:Z 往后移是 a 。

数字和其它的符号都不做变换。

数据范围: 输入的字符串长度满足 1 \le n \le 100 \1≤n≤100 

输入描述:

输入一组密码,长度不超过100个字符。

输出描述:

输出密码变换后的字符串

示例1

输入:

YUANzhi1987

输出:

zvbo9441987

题目的主要信息:

  • 给字符串加密,输入多个明文字符串,长度不超过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),n为字符串长度,遍历一次字符串
  • 空间复杂度:O(1)O(1),无额外空间

方法二:打表

具体做法:

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

#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),n为字符串的长度,一次遍历
  • 空间复杂度:O(1)O(1),常数级空间