【面试题46 把数字翻译成字符串】
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
Leetcode题目对应位置: 面试题46:把数字翻译成字符串
思路:动态规划问题。
观察发现,不断扩展一个数字串时,如果新添加的数字和前一位数字不能合并为一个可转化为字符的两位数,那么新添加的数字对整体能够实现的翻译数量并没有贡献。
比如 “4” 有一种翻译方式,再添加一个数字 3 形成 “43”,仍然只有一种翻译方法,就是两个数字分别翻译。
当新添加的数字能够和前一位数字形成一个可被翻译为字符的两位数时,新添加的这个数字对整体可被翻译的数量贡献为:dp[i-1] + dp[i-2]
,即前两位状态的和。
比如 “134” 有两种翻译方式,再添加一个数字 2 形成 “1342”,此时 2 对整体无贡献,“1342” 仍然只有 2 种翻译方式;继续添加数字 1,形成 “13421”,此时 1 可以和前面的 2 合并为 21 翻译,也可以单独翻译。当选择单独翻译时,其翻译个数就是数字 “1342” 的翻译个数(状态),即 2;当选择合并翻译时,将 21 看作一个整体,其翻译个数就是数字 “134” 的翻译个数,即 2。所以添加 1 后,总的翻译个数等于 2 + 2 = 4。是不是想到了斐波那契数列?
class Solution:
def translateNum(self, num: int) -> int:
s = str(num)
n = len(s)
pre, p1, p2 = s[0], 1, 1
for i in range(2, n+1):
cur = int(pre + s[i-1])
if cur >= 10 and cur < 26:
p = p1 + p2
else:
p = p2
p1, p2 = p2, p
pre = s[i-1]
return p2
这道题属于斐波那契数列数列的变体,当满足条件 10 <= cur < 26
时,新增加的一位状态转移为 dp[i] = dp[i-1] + dp[i-2]
;当不满足条件时,状态转移为 dp[i] = dp[i-1]
。另外斐波那契数列问题不需要真的创建 dp 数组,只要用两个变量(p1,p2)滚动维护即可。