題目來源:力扣(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 個數字被翻譯的時候,可能出現兩種狀況:
根據上面的翻譯規則,能夠求得轉移方程(具體參考上面的解析):