1. 程式人生 > >Leetcode 91. Decode Ways 解碼方法(動態規劃,字符串處理)

Leetcode 91. Decode Ways 解碼方法(動態規劃,字符串處理)

範圍 解碼 length emp 添加 substr temp 字母 decode

Leetcode 91. Decode Ways 解碼方法(動態規劃,字符串處理)

題目描述

一條報文包含字母A-Z,使用下面的字母-數字映射進行解碼

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

給一串包含數字的加密報文,求有多少種解碼方式
舉個例子,已知報文"12",它可以解碼為AB(1 2),也可以是L (12)
所以解碼方式有2種。

測試樣例

Input:
"0"
"121212"
"101010"
"1001"
"0101"
Output:
0
13
1
0
0

詳細分析

這道題不難,不過corner cases比較多,需要仔細分析。先考慮1212這個例子:(為了表達方便,我們用逗號分隔表示每種解碼方式而不用扳手指算,比如1212的一種解碼方式為12,12而不用L,L)

1=>

1

12=>

1,2
12

121=>

1,2,1
1,21
12,1

1212=>

1,2,1,2
1,21,2
12,1,2
1,2,12
12,12

到這裏就可以總結出規律了,對於1212,其實是兩種解碼的和:

1,2,1,(2)
1,21,(2)
12,1,(2)
-----------
1,2,(12)
12,(12)

分割線上面是121的解碼方式,並在後加以當前下標的2,分割線下面是12

的解碼方式加以當前下標和前一個下標表示的字符。

可以看出,如果當前字符和前面一個字符可以構成>10 && <=26(不包括20,至於為什麽等下說)的字符,那麽當前解碼方式就是:

dp[i]=dp[i-1]+dp[i-2]

現在考慮一些corner case,如果當前字符是0,那麽它並不符合上面的遞推公式,考慮2020:
20=>

20

202=>

20,2

2020=>

20,(20)

可以看到2020,由於0不在解碼範圍內,所以它不能與前一項通過添加後綴的方式構成解碼方式,它只是簡單等於前兩項然後加上後綴20,同理還有10。

按照這種思路,我們可以得出下面的狀態轉移:

let x = s.substr(i-1,2);
x>0 && x<10:    dp[i]=dp[i-1]
x==10:          dp[i]=dp[i-2]
x>10&&x<20:     dp[i]=dp[i-1]+dp[i-2]
x==20:          dp[i]=dp[i-2]
x>20&&x<=26:    dp[i]=dp[i-1]+dp[i-2]
x>26&&x%10!=0: dp[i]=dp[i-1];
x>26&&x%10==0: return 0

代碼實現

代碼太爛湊合看吧...

class Solution {
public:
    int numDecodings(string s) {
        if(s.length()==0){
            return 0;
        }
        if(s[0]=='0'){
            return 0;
        }
        if(s.length()==1){
            return 1;
        }
        int dp[100000];
        dp[0]=1;
        std::string ns = s.substr(0,2);
        int t = atoi(ns.c_str());

        if(t>0 && t<10){
            return 0;
        }else if(t==10){
            dp[1]=1;
        }else if(t>10 && t<20){
            dp[1]=2;
        }else if(t==20){
            dp[1]=1;
        }else if(t>20 && t<=26){
            dp[1]=2;
        }else if(t>26 && t%10!=0){
            dp[1]=1;
        }else{
            return 0;
        }
        if(s.length()==2){
            return dp[1];
        }

        for(int i=2;i<s.length();i++){
            std::string tempStr = s.substr(i-1,2);
            int n = atoi(tempStr.c_str());

            if((n>26 && n%10!=0)||(n>0 && n<10)){
                dp[i]=dp[i-1];
            }else if(n>10 && n<=26&& n!=20){
                dp[i]=dp[i-1]+dp[i-2];
            }else if(n==10 || n==20){
                dp[i]=dp[i-2];
            }else if(n==0 || n%10==0){
                return 0;
            }
        }
        return dp[s.length()-1];
    }
};

Leetcode 91. Decode Ways 解碼方法(動態規劃,字符串處理)