解码字母到整数映射

标签: 字符串

难度: Easy

给你一个字符串 s,它由数字('0' - '9')和 '#' 组成。我们希望按下述规则将 s 映射为一些小写英文字符:

  • 字符('a' - 'i')分别用('1''9')表示。
  • 字符('j' - 'z')分别用('10#' - '26#')表示。 

返回映射之后形成的新字符串。

题目数据保证映射始终唯一。

示例 1:

输入:s = "10#11#12"
输出:"jkab"
解释:"j" -> "10#" , "k" -> "11#" , "a" -> "1" , "b" -> "2".

示例 2:

输入:s = "1326#"
输出:"acz"

提示:

  • 1 <= s.length <= 1000
  • s[i] 只包含数字('0'-'9')和 '#' 字符。
  • s 是映射始终存在的有效字符串。

Submission

运行时间: 25 ms

内存: 16.1 MB

class Solution:
    def freqAlphabets(self, s: str) -> str:
        result = ""
        i = 0
        while i < len(s):
            if i + 2 < len(s) and s[i + 2] == '#':
                num = int(s[i:i+2])
                result += chr(num - 1 + ord('a'))
                i += 3
            else:
                num = int(s[i])
                result += chr(num - 1 + ord('a'))
                i += 1
        return result

solution = Solution()

print(solution.freqAlphabets("10#11#12"))  # Output: jkab
print(solution.freqAlphabets("1326#"))     # Output: acz

Explain

这个问题可以通过遍历字符串来解决。遍历时,首先检查当前位置后两个字符是否为'#'。如果是,说明当前数字是两位数(10到26之间),需要将其转换为相应的字母('j'到'z')。否则,当前数字是一位数(1到9之间),直接转换为相应的字母('a'到'i')。转换方法是将数字字符转为整数,然后通过加上ASCII码的'a'的值减一来获取对应的字母。遍历完成后,得到的结果字符串即为答案。

时间复杂度: O(n)

空间复杂度: O(n)

class Solution:
    def freqAlphabets(self, s: str) -> str:
        result = ""  # 结果字符串
        i = 0  # 初始索引为0
        while i < len(s):  # 遍历字符串
            if i + 2 < len(s) and s[i + 2] == '#':  # 检查是否为两位数
                num = int(s[i:i+2])  # 取两位数
                result += chr(num - 1 + ord('a'))  # 转换为字母并添加到结果
                i += 3  # 移动三位索引,跳过'#'
            else:
                num = int(s[i])  # 取一位数
                result += chr(num - 1 + ord('a'))  # 转换为字母并添加到结果
                i += 1  # 移动一位索引
        return result  # 返回结果字符串

solution = Solution()

print(solution.freqAlphabets("10#11#12"))  # Output: jkab
print(solution.freqAlphabets("1326#"))     # Output: acz

Explore

根据题目的定义,每个数字应该是1到26之间的有效整数,因此以'0'开头的输入(如'01#'或'012')不符合有效编码规则。如果输入确实包含这类数据,算法应该设计为先验证输入的合法性。在当前的实现中,若强行解析这样的输入,'0'会被忽略或引发错误,因为'0'不对应任何有效字母。正确的做法是在解析前增加输入验证,确保所有字符均符合1到26的范围,并且没有不合规的'0'出现。

当前的解码算法假设输入格式是正确的,即每个'#'都正确地跟随两个数字。如果实际输入包含连续的'#'或位置不正确的'#'(如'##'或'#10#'),这会导致解析错误或未定义行为。为了确保算法的健壮性,应在实际解码前增加一个预处理步骤,检查并验证'#'的位置和前面是否有两个数字。如果发现格式错误,应当抛出异常或返回错误信息,而不是尝试进行错误的解码。

在给定的算法实现中,如果字符串末尾的数字不足三位且不含'#',例如'12345',算法会自动处理这些数字。算法通过检查每个数字右侧是否有两个字符以及是否跟随'#'来决定如何解码。对于末尾的'45',由于它们后面没有'#',算法会将它们视为单独的数字('4'和'5'),并分别转换为对应的字母。这是通过在循环中处理每个单一数字直到字符串结束来实现的。

如果输入字符串包含非数字字符,使用int(s[i:i+2])尝试将这些字符转换为整数时,将引发ValueError异常,因为int()函数只能将纯数字字符串转换为整数。这种情况下的行为并未在当前算法中明确处理,因此标准做法应包括对输入字符串的有效性进行验证,确保所有字符都是合法的数字或'#'。如果检测到非法字符,应当抛出异常或返回适当的错误信息,以避免执行无效或错误的转换。