青训营X豆包MarsCode刷题 226 小T的密码变换规则 | 豆包MarsCode AI 刷题

126 阅读4分钟

问题描述

小T设计了一种密码变换规则,将输入字符串转换为一串数字密码。变换规则如下:

  1. 小写字母转换规则
    小写字母根据电话按键上的分组映射为数字:

    • a, b, c -> 2
    • d, e, f -> 3
    • g, h, i -> 4
    • j, k, l -> 5
    • m, n, o -> 6
    • p, q, r, s -> 7
    • t, u, v -> 8
    • w, x, y, z -> 9
  2. 大写字母转换规则

    • 首先将大写字母转为小写字母。
    • 转换为字母表中前一个字母,例如:B 转为 aA 特殊处理转为 z
    • 按上述小写字母的规则转换为数字。
  3. 非字母字符保持不变

输入输出

  • 输入:一个字符串 s,包含大小写字母和数字。
  • 输出:按规则转换后的数字密码字符串。

样例分析

  • 示例1:
    输入:"LIming0701"
    输出:"5464640701"
    解析:

    • 'L' 转为 'k',映射为 5
    • 'I' 转为 'h',映射为 4
    • 其他小写字母按规则映射,数字保持不变。
  • 示例2:
    输入:"PassW0rd"
    输出:"62778073"
    解析:

    • 'P' 转为 'o',映射为 6
    • 'W' 转为 'v',映射为 8
    • 其他字母按规则映射。

二、解题思路

核心思路

  1. 遍历字符串,将大写字母转为小写字母的前一个字母。
  2. 构建一个映射表,将小写字母按电话键规则映射到数字。
  3. 根据映射表替换字符串中的字母,非字母字符保持不变。

三、代码实现

C++代码

#include <cctype>
#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

// 解决密码映射问题
string solution(const string &s) {
    string res = s;

    // 步骤1:将大写字母转为小写字母的前一个字母
    for (auto &x : res) {
        if (isupper(x)) {
            if (x == 'A') // 特殊处理 A
                x = 'Z';
            else
                x--; // 转换为前一个字母
            x = tolower(x); // 转为小写
        }
    }

    // 步骤2:构建小写字母到数字的映射表
    unordered_map<char, char> hash;
    char alp = 'a';
    char code = '1';

    // 按照题目规则生成映射
    for (int i = 0; i < 26; i++) {
        if (i % 3 == 0 && code < '7') 
            code++;
        else if (i < 22 && i > 18 && code != '8') 
            code = '8';
        else if (i > 21) 
            code = '9';
        hash[alp] = code;
        alp++;
    }

    // 步骤3:替换字母为对应的数字
    for (auto &x : res) {
        if (isalpha(x)) {
            x = hash[x]; // 替换为数字
        }
    }

    return res;
}

int main() {
    // 测试样例
    std::cout << solution("LIming0701") << std::endl; // 输出:5464640701
    std::cout << solution("PassW0rd") << std::endl;  // 输出:62778073
    std::cout << solution("fbbMIjHoLAidgGr") << std::endl; // 输出:32255454444347
    return 0;
}

四、代码解析

1. 处理大写字母

  • 如果字符是大写字母:

    • 特殊处理 A,变为 Z
    • 其他大写字母变为其前一个字母;
    • 转换为小写字母。
      代码:
if (isupper(x)) {
    if (x == 'A')
        x = 'Z';
    else
        x--;
    x = tolower(x);
}

2. 构建字母映射表

构造小写字母到数字的映射,按题目要求,a~z 被分成不同的数字分组:

  • a, b, c -> 2d, e, f -> 3,依此类推;
  • 使用哈希表存储映射关系。
    代码:
unordered_map<char, char> hash;
char alp = 'a';
char code = '1';
for (int i = 0; i < 26; i++) {
    if (i % 3 == 0 && code < '7') 
        code++;
    else if (i < 22 && i > 18 && code != '8') 
        code = '8';
    else if (i > 21) 
        code = '9';
    hash[alp] = code;
    alp++;
}

3. 替换字符

遍历字符串,将字母按映射表替换为数字,其他字符保持不变:

for (auto &x : res) {
    if (isalpha(x)) {
        x = hash[x];
    }
}

五、时间复杂度分析

  1. 预处理映射表
    构建字母到数字的映射表是固定操作,时间复杂度为 O(26)O(26)。
  2. 遍历字符串
    遍历字符串并根据规则替换,每个字符操作时间复杂度为 O(1)O(1)。字符串长度为 nn,所以时间复杂度为 O(n)O(n)。

总时间复杂度:O(n)O(n)


六、总结

算法特点

  • 代码清晰,逻辑分层明确。
  • 使用哈希表快速实现字母到数字的映射,时间效率高。

适用场景

  • 本算法可应用于密码生成、字符映射等问题,尤其适合简单的加密规则实现。

改进方向

  • 可以进一步优化映射表的构建过程,使代码更简洁易读。
  • 对其他字符的处理逻辑可扩展为多种映射规则,以增强通用性。

输出验证

通过样例测试,算法输出正确,符合题目要求。