题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcofpython
给定一个数字,咱们按照以下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不一样的翻译方法。面试
示例 1:编程
输入: 12258 输出: 5 解释: 12258有5种不一样的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:bash
思路:动态规划函数
先理清题意,题目中说明规则: 0 翻译成 "a", 1 翻译成 "b",...,25 翻译成 "z"。并且题目中也说明【一个数字可能有多个翻译】。那么这里就能够想到,当数字大于等于 10 小于等于 25 的时候,这部分的数字能够看出是两个单独数字组成,或者单独当成一个数字。spa
如今看示例 1:翻译
输入: 12258 输出: 5 解释: 12258有5种不一样的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
看下面的解释中,咱们能够看到:code
[1, 2 ,2, 5, 8]
剩下的 4 个就是连续两位数字可考虑组合的状况blog
在上面的示例中,'58' 这个组合是不成立的,咱们知道组合的数字的范围应该落在 [10, 25] 之间。leetcode
那么也就是说,翻译的规则,在字符串的第 i 个位置中能够分为两种状况:
如今假设将题目给出的数字 num 第 i 个数字记为 $x_i$,例如示例中的 num = 12258,那么 $x_1$ 就是 1。
如今定义动态规划列表 dp,假设 dp[i] 为 $x_i$ 结尾的数字的翻译方案。
按照前面得出的翻译规则总结出转移方程。
当 $x_{i-1}$ 和 $x_i$ 两个数字组合可被翻译时,这里就会有两种状况。单独翻译,或者组合翻译。也就是:
若是 $x_{i-1}$ 和 $x_i$ 两个数字没法组合,那么就只能当成单个数字进行翻译。因此 dp[i] = dp[i-1]。
这里须要注意的可组合数字落在的区间是 [10, 25],前面已经说明了,只有这种状况才可以成功组合被翻译。
还有一种状况,就是 $x_{i-1}$ 为 0 的时候,这种状况能够会出现 00, 01, 02, ...
这样的组合数字。可是这种状况是不可以被翻译的。
因此最终的状态转移方程,以及具体落在的区间:
$$ dp[i] = \begin{cases} dp[i-2] + dp[i-1], & 10x_{i-1} + x_i \in [10, 25] \\ dp[i-1] & 10x_{i-1} + x_i \in [0, 10) \bigcup (25, 99] \end{cases} $$
注意,这里咱们并不考虑三位数的组合
在这里,dp[i] 表示的是以 $x_i$ 结尾的数字的翻译方案。当 i=0 和 i=1 的时候,表示的是【无数字】和【第一个数字】。这里都初始化为 1。(前面说明了 $x_1$ 表示的是第 1 个数字,如题目 12258 中的第一个数字 1。)
反向推导 dp[0] 的值,假设当出现两个数字可以组合且被翻译的状况下,例如12
,那么 dp[2] 显然是等于 2。要么以[1, 2]
的形式,要么以[12]
的形式进行翻译。
此时 dp[2] = dp[1] + dp[0] = 2,而 dp[1] 为 1,那么 dp[0] = 1。
而最终咱们须要求得的结果就是 dp[n]
,也就是题目中所需求的翻译方案(n 表示的是数字长度。)
在这里可使用字符串截取的方法去实现,这里须要将数字下转换为字符串,缺点是字符串会占用必定的空间。这里采用字符串截取的方法来求解。还有一种方法是使用取模的方法(可考虑尝试)
具体的代码以下。
class Solution: def translateNum(self, num: int) -> int: string = str(num) n = len(string) dp = [0] * (n+1) dp[0]=1 dp[1]=1 for i in range(2, n + 1): if "10" <= string[i-2:i] <="25": dp[i] = dp[i-1] + dp[i-2] else: dp[i] = dp[i-1] return dp[n]
本题使用的动态规划,先分析题意,找出翻译的规则。能够发现,当第 i 个数字被翻译的时候,可能出现两种状况:
根据上面的翻译规则,能够求得转移方程(具体参考上面的解析):