91. 解码方法
题目
一条包含字母 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 位 的整数。
分析
简单的动态分析,dp[i]=dp[i-1]+dp[i-2],主要难点在于边界条件。
当当前char为0时,如果是字符串首尾||前一个char为0或者前一个char+0大于26,则不符合条件,返回0;否则dp[i] = dp[i-2],因为当前char必须与前一个结合。
当当前char不为0时,last_char+cur_char在[1,26]内,dp[i] = dp[i-1]+dp[i-2],否则dp[i] = dp[i-1];
上述过程只用到dp[i-2],dp[i-1],dp[i],所以可以优化。用三个变量存储
注:官方代码简洁一点
代码
public int numDecodings(String s) {
if(Integer.parseInt(s.substring(0,1))==0) return 0;
int[] dp = new int[s.length()+1];
dp[0] = 1;
dp[1] = 1;
for(int i=2;i<dp.length;i++){
if(Integer.parseInt(s.substring(i-1,i))==0){
if(Integer.parseInt(s.substring(i-2,i))==0 || Integer.parseInt(s.substring(i-2,i))>26){
return 0;
}
else {
dp[i] = dp[i-2];
}
}
else if(Integer.parseInt(s.substring(i-2,i-1))!=0 && Integer.parseInt(s.substring(i-2,i))>10 && Integer.parseInt(s.substring(i-2,i))<=26){
dp[i] = dp[i-1]+dp[i-2];
}
else{
dp[i] = dp[i-1];
}
}
return dp[s.length()];
}
// 优化后
public int numDecodings(String s) {
if(Integer.parseInt(s.substring(0,1))==0) return 0;
int left = 1;
int right = 1;
int temp;
for(int i=1;i<s.length();i++){
if(Integer.parseInt(s.substring(i,i+1))==0){
if(Integer.parseInt(s.substring(i-1,i+1))==0 || Integer.parseInt(s.substring(i-1,i+1))>26){
return 0;
}
else {
temp = right;
right = left;
left = temp;
}
}
else if(Integer.parseInt(s.substring(i-1,i))!=0 && Integer.parseInt(s.substring(i-1,i+1))>10 && Integer.parseInt(s.substring(i-1,i+1))<=26){
temp = left + right;
left = right;
right = temp;
}
else{
left = right;
}
}
return right;
}
结果
时间超过35.39%
内存超过5.03%