1. 程式人生 > 其它 >[題解]劍指 Offer 46. 把數字翻譯成字串 (C++)

[題解]劍指 Offer 46. 把數字翻譯成字串 (C++)

題目

給定一個數字,我們按照如下規則把它翻譯為字串:0 翻譯成 “a” ,1 翻譯成 “b”,……,11 翻譯成 “l”,……,25 翻譯成 “z”。一個數字可能有多個翻譯。請程式設計實現一個函式,用來計算一個數字有多少種不同的翻譯方法。

示例 1:

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

提示:

\(0 <= num < 2^{31}\)

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof


著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

思路

這題看到的第一反應就是用動態規劃了,先把數字轉換成字串來考慮會方便一點,但是假設我們用dp[i]來表示前i個數字翻譯方法數,怎麼更新dp陣列呢?其實可以把結尾處的數字數也作為一個資訊,用一個二維陣列,dp[0][i]表示前i個數字,最後一個數字單獨翻譯的翻譯數;dp[1][i]表示前i個數字,最後兩個數字一起翻譯的翻譯數。dp[0][i]可以從dp[0][i-1]和dp[1][i-1]轉移過來,因為最後一個數字無所謂是什麼都可以翻譯;dp[1][i]就只能從dp[0][i-1]轉移過來,而且s[i-1]和s[i]組成的數字必須在10~25這個範圍內。
這樣,我們就能得到轉移方程了:

\[\left\{\begin{array}{l}dp\lbrack0\rbrack\lbrack i\rbrack\;=\;dp\lbrack0\rbrack\lbrack i\;-\;1\rbrack\;+\;dp\lbrack1\rbrack\lbrack i\;-\;1\rbrack\\dp\lbrack1\rbrack\lbrack i\rbrack\;=\;\left\{\begin{array}{l}dp\lbrack0\rbrack\lbrack i\;-\;1\rbrack,\;s\lbrack i\;-\;1\rbrack\;=='1'\;\vert\vert\;(s\lbrack i\;-\;1\rbrack\;==\;'2'\;\&\&\;s\lbrack i\rbrack\;<\;'6')\\0,\;else\end{array}\right.\end{array}\right. \]

時間複雜度和空間複雜度都是O(n)。

程式碼

class Solution {
public:
    int translateNum(int num) {
        string s = to_string(num);
        int n = s.size();
        vector<vector<int>> dp(2, vector<int>(n));
        dp[0][0] = 1;
        dp[1][0] = 0;
        for(int i = 1; i < n; ++i)
        {
            dp[0][i] = dp[0][i - 1] + dp[1][i - 1];
            if(s[i - 1] == '1')
            {
                dp[1][i] = dp[0][i - 1];
            }
            else if(s[i - 1] == '2')
            {
                if(s[i] > '5')
                {
                    dp[1][i] = 0;
                }
                else{
                    dp[1][i] = dp[0][i - 1];
                }
            }
            else
            {
                dp[1][i] = 0;
            }
        }
        return dp[0].back() + dp[1].back();
    }
};

改進

仔細考慮更新dp陣列的過程,會發現在更新dp陣列在位置i的資訊時,只會用到最近一次更新後的dp[0][i - 1]和dp[1][i - 1],那麼可以只用兩個數dp1和dp2來更新,空間複雜度降低到O(1)。

程式碼

class Solution {
public:
    int translateNum(int num) {
        string s = to_string(num);
        int n = s.size();
        int dp1 = 1, dp2 = 0;
        for(int i = 1; i < n; ++i)
        {
            int tmp1 = dp1;
            dp1 = dp1 + dp2;
            if(s[i - 1] == '1')
            {
                dp2 = tmp1;
            }
            else if(s[i - 1] == '2')
            {
                if(s[i] > '5')
                {
                    dp2 = 0;
                }
                else{
                    dp2 = tmp1;
                }
            }
            else
            {
                dp2 = 0;
            }
        }
        return dp1 + dp2;
    }
};