数字翻译成字符串的可能性
问题描述
小M获得了一个任务,需要将数字翻译成字符串。翻译规则是:0对应"a",1对应"b",依此类推直到25对应"z"。一个数字可能有多种翻译方法。小M需要一个程序来计算一个数字有多少种不同的翻译方法。
测试样例
样例1:
输入:
num = 12258
输出:5
样例2:
输入:
num = 1400112
输出:6
样例3:
输入:
num = 2110101
输出:10
样例4:
输入:
num = 25
输出:2
样例5:
输入:
num = 1023
输出:4
解题思路
这个问题可以通过动态规划来解决:用一个数组 dp 来记录从数字开头到当前位置有多少种翻译方法
动态规划其实就是 用小问题的答案,来推导大问题的答案。我们可以按以下步骤逐步解决:
-
如果数字是空的,没有翻译方法,所以答案是0
-
如果数字只有1位,比如 "5",它只能翻译成一个字母("f"),所以答案是1
-
当数字有多位时,比如 "122",我们从左到右一位一位地检查:
- 看当前数字(最后一位)能不能单独翻译
- 看当前数字和前一位数字能不能合并翻译
-
每次把这些方法数加起来,就得到前面所有数字能翻译的总方法数
具体例子
对于数字 12258 的翻译过程:
-
开始时,
1只能单独翻译为b,方法数是1 -
读到
12时:2可以单独翻译,继承前面的1种方法12可以合并翻译,这是另一种方法- 所以到
12为止,方法数是1(b+b)+ 1(m)= 2
-
读到
122时:- 最后一位
2可以单独翻译,继承前面2种方法 - 最后两位
22也可以合并翻译,这又是2种方法 - 所以到
122为止,方法数是2+2=4
- 最后一位
-
继续到
1225时:- 最后一位
5可以单独翻译,继承前面4种方法 - 最后两位
25可以合并翻译,这又是4种方法 - 所以到
1225为止,方法数是4+4=8
- 最后一位
-
最后到
12258时:- 最后一位
8可以单独翻译,继承前面8种方法 - 最后两位
58超出了范围,不能合并翻译 - 所以到
12258为止,方法数是8+0=8
- 最后一位
动态规划
dp 定义:用 dp[i] 表示数字从第 0 位到第 i 位的子串可以翻译的不同方式数
状态转移方程:
- 单独翻译当前数字:
dp[i] += dp[i-1]。 - 如果与前一个数字组成一个两位数,且该两位数在范围 10-25 内,则
dp[i] += dp[i-2]
则最后的答案为: dp[n]
代码实现:使用Python举例
def solution(num):
# 转成字符串以便逐位处理
num_str = str(num)
n = len(num_str)
# 边界情况
if n == 0:
return 0
if n == 1:
return 1
# 初始化dp数组
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
# 动态规划求解
for i in range(2, n + 1):
# 单独翻译当前数字
dp[i] += dp[i-1]
# 与前一个数字组成两位数
two_digit = int(num_str[i-2:i]) # 两位数
if 10 <= two_digit <= 25:
dp[i] += dp[i-2]
return dp[n]
复杂度分析:
- 时间复杂度:
O(n),其中 n 是数字的位数,因为我们遍历了一遍数字 - 空间复杂度:
O(n),用于存储 DP 数组