一条包含字母 A-Z
的消息通过以下映射进行了 编码 :
'A' -> "1" 'B' -> "2" ... 'Z' -> "26"
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106"
可以映射为:
"AAJF"
,将消息分组为(1 1 10 6)
"KJF"
,将消息分组为(11 10 6)
注意,消息不能分组为 (1 11 06)
,因为 "06"
不能映射为 "F"
,这是由于 "6"
和 "06"
在映射中并不等价。
给你一个只含数字的 非空 字符串 s
,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 32 位 的整数。
class Solution {
public int numDecodings(String s) {
s = " " + s;
int len = s.length();
int[] dp = new int[len];
char[] c = s.toCharArray();
dp[0] = 1;
for(int i = 1; i < len; i++){
int cur = c[i] - '0';
int pre = c[i-1] - '0';
int total = pre * 10 + cur;
if(1 <= cur && cur<= 9 ){
//能单独作为一个item, 后缀在原始字符串后面
dp[i] = dp[i-1];
}
if( 10 <= total && total <= 26){
//能够和前一个组成item,后缀在原始字符串后面
dp[i] += dp[i-2];
}
}
return dp[len-1];
}
}
解析:
对于这个问题,特殊的数字是0,那么我们主要看当前数字是否是0,以及前一个数字是否是0. 规定两种合法 的item : 当前数字不为0, 当前数字和前一个数字构成的整体10 <= x <= 26,也就是说不能超过这个范围,注意,是不可能出现连续两个都是0的,这样是不可能有答案的。
如果当前数字是合法的: 将其挂在之前dp[i-1]序列之后,必然是合法的,且不增加组合数(参考2 9)这种组合 dp[i] = dp[i-1]
如果当前数字加上前一个数字是合法的: 那么将最后一个数字拆下来,和当前数字拼起来挂到dp[i-2]上,也是合法的。 dp[i] = dp[i-2]
如果当前数字合法,且和前一个数字组合也合法,那么dp[i] = dp[i-1] + dp[i-2]
开头的空字符串拼接是为了不判断首个字符是否为0;