1. 程式人生 > 實用技巧 >【LeetCode-動態規劃】解碼方法

【LeetCode-動態規劃】解碼方法

題目描述

一條包含字母 A-Z 的訊息通過以下方式進行了編碼:

'A' -> 1
'B' -> 2
...
'Z' -> 26

示例:

輸入: "12"
輸出: 2
解釋: 它可以解碼為 "AB"(1 2)或者 "L"(12)。

輸入: "226"
輸出: 3
解釋: 它可以解碼為 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

題目連結: https://leetcode-cn.com/problems/decode-ways/

思路

使用動態規劃求解。

  • 狀態定義:dp[i] 表示前 i 個字元(s[0:i-1])的解碼數,i ∈ [0, n];
  • 邊界條件:dp[0] = 1(這一個很重要),dp[0] = 1(在 s[0]!='0' 的情況下);
  • 狀態轉移:
    • dp[i] 表示前 i 個字元(s[0:i-1])的解碼數,所以我們要考慮 s[i-1] 以及之前的字元情況;
    • 如果 s[i-1] = '0':
      • 如果 s[i-2] = '1' 或者 s[i-2] = '2',這樣能把 s[i-1] 和 s[i-2] 當成一個整體來看待('10' 或者 '20'),這樣的話解碼數沒有增加,也就是 dp[i] = dp[i-2];
      • 否則的話,無法解碼,例如 '30' 或者 '40' 等,返回 0;
    • 否則,如果 s[i-1] != '0':
      • 如果 s[i-2]=='1',這樣無論 s[i-1] 為多少,都能進行兩種解碼:s[i-2]、s[i-1] 當做一個整體解碼和兩者分開解碼,所以 dp[i] = dp[i-1] + dp[i-2],dp[i-1] 對應分開解碼,dp[i-2] 對應整體解碼;
      • 如果 s[i-2]=='2' 並且 s[i-1]<'7',這樣也可以進行兩種解碼(和上面一種情況一樣),所以 dp[i] = dp[i-1] + dp[i-2];
      • 否則,上面兩種情況都不滿足,則 s[i-1] 只能單獨解碼,也就是 dp[i] = dp[i-1];

由於 dp[i] 表示前 i 個字元(s[0:i-1])的解碼數,所以 dp 的長度為 n+1,最終返回 dp[n] 表示前 n 個字元的解碼(str[0:n-1])。
程式碼如下:

class Solution {
public:
    int numDecodings(string s) {
        if(s[0]=='0') return 0;

        int n = s.size();
        vector<int> dp(n+1, 0);
        dp[0] = 1;  // 注意要設為 1
        dp[1] = 1;
        for(int i=2; i<=n; i++){
            if(s[i-1]=='0'){
                if(s[i-2]=='1' || s[i-2]=='2') dp[i] = dp[i-2];
                else return 0;
            }else{
                if(s[i-2]=='1' || s[i-2]=='2'&&s[i-1]<'7') dp[i] = dp[i-1] + dp[i-2];
                else dp[i] = dp[i-1];
            }
        }
        return dp[n];
    }
};
  • 時間複雜度:O(n)
  • 空間複雜度:O(1)