LeetCode 面試題46. 把數字翻譯成字符串 | Python

面試題46. 把數字翻譯成字符串


題目來源:力扣(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 <= num < 231

解題思路


思路:動態規劃函數

先理清題意,題目中說明規則: 0 翻譯成 "a", 1 翻譯成 "b",...,25 翻譯成 "z"。並且題目中也說明【一個數字可能有多個翻譯】。那麼這裏就能夠想到,當數字大於等於 10 小於等於 25 的時候,這部分的數字能夠看出是兩個單獨數字組成,或者單獨當成一個數字。spa

如今看示例 1:翻譯

輸入: 12258
輸出: 5
解釋: 12258有5種不一樣的翻譯,分別是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

看下面的解釋中,咱們能夠看到:code

  • "bccfi" 這種狀況就是將全部的數字單獨翻譯,便是 [1, 2 ,2, 5, 8]
  • 剩下的 4 個就是連續兩位數字可考慮組合的狀況blog

    • [1, 22, 5, 8] 對應翻譯的是 "bwfi"
    • [1, 2, 25, 8] 對應翻譯的是 "bczi"
    • [12, 2, 5, 8] 對應翻譯的是 "mcfi"
    • [12, 25, 8] 對應翻譯的是 "mzi"

在上面的示例中,'58' 這個組合是不成立的,咱們知道組合的數字的範圍應該落在 [10, 25] 之間。leetcode

那麼也就是說,翻譯的規則,在字符串的第 i 個位置中能夠分爲兩種狀況:

  • 單獨進行翻譯
  • 若是與 i - 1 位可以組合成數字且落在 [10, 25],那麼能夠連起來翻譯。

如今假設將題目給出的數字 num 第 i 個數字記爲 $x_i$,例如示例中的 num = 12258,那麼 $x_1$ 就是 1。

如今定義動態規劃列表 dp,假設 dp[i] 爲 $x_i$ 結尾的數字的翻譯方案。

按照前面得出的翻譯規則總結出轉移方程。

當 $x_{i-1}$ 和 $x_i$ 兩個數字組合可被翻譯時,這裏就會有兩種狀況。單獨翻譯,或者組合翻譯。也就是:

  • 當組合翻譯的時候,$x_{i-1}x_i$ 組合肯定,前面 i-2 個數的翻譯方案爲 dp[i-2]。
  • 當單獨翻譯的時候,$x_i$ 肯定,前面 i-1 個數的翻譯方案爲 dp[i-1]。
  • 也就是說當 $x_{i-1}$ 和 $x_i$ 兩個數字組合可被翻譯的時候,可由上述兩種狀況結合,最終 dp[i] = dp[i-2] + dp[i-1]。

若是 $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 個數字被翻譯的時候,可能出現兩種狀況:

    • 單獨翻譯第 i 個位置的數字
    • 當第 i 個位置的數字與第 i-1 位置的數字組合且可被翻譯,那麼可考慮組合進行翻譯
  • 根據上面的翻譯規則,能夠求得轉移方程(具體參考上面的解析):

    • 當兩個連續數字可以組合的狀況下:dp[i] = dp[i-2]+dp[i-1]
    • 不然:dp[i]=dp[i-1]
  • 對動態規劃列表進行初始化,肯定最終求解的值爲 dp[n]。
相關文章
相關標籤/搜索