A message containing letters from A-Z
is being encoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12"
, it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding "12"
is 2.
public int numDecodings(String s) {
if (s == null || s.length() == 0 || s.charAt(0) == '0') return 0;
int[] dp = new int[s.length()+1];
dp[0] = dp[1] = 1;
for (int i = 1; i < s.length(); i++) {
char pre = s.charAt(i-1);
char c = s.charAt(i);
if (c == '0') {
if (pre > '2' || pre == '0') return 0;
else dp[i+1] = dp[i-1];
} else {
dp[i+1] = dp[i];
if (pre != '0' && (pre-'0')*10 + (c-'0') <= 26) dp[i+1] += dp[i-1];
}
}
return dp[dp.length-1];
}
此方法是从前往后递推,dp[i+1]是指以s.substring(0,i+1)字串的解,但是此代码比较繁杂,因为就是0这个坑。
看下面的代码:
public int numDecodings(String s) {
int n = s.length();
if (n == 0) {
return 0;
}
int[] table = new int[n+1];
table[n] = 1;
table[n-1] = s.charAt(n-1) != '0' ? 1 : 0;
for (int i = n-2; i >= 0; i--) {
if (s.charAt(i) == '0') {
table[i] = 0;
} else {
int num = Integer.parseInt(s.substring(i, i+2));
if (num <= 26) {
table[i] = table[i+1]+table[i+2];
} else {
table[i] = table[i+1];
}
}
}
return table[0];
}
其实状态转移方程是基本一样的,差别就是一个从开始扫描,一个从数组尾部扫。从尾部扫描的一个好处是当s[i] = 0的时候,此时dp[i] = 0,因为以0开头的字符串都是不合法的,都是0。而以0结尾的字符串你不能直接按0,所以有很复杂的条件语句。这一点就决定了从尾部扫描要比从头扫描要简单。
另外一种思考问题的方法,从头到尾,还是从尾到头。一些问题逆向比较简单。