Leetcode 91. Decode Ways 解碼方法(動態規劃,字符串處理)
阿新 • • 發佈:2018-02-19
範圍 解碼 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 解碼方法(動態規劃,字符串處理)