问题:
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).
解决:
① 给定一个已经编码过的字符串,判断有几种解码方式。例如:
“12” ---> “AB”,“L”。
“125” ---> “ABE”,“AY”,“LE”
由编码规则可知,编码范围为1 ~ 26,可以知道,一个大写字母可以编码至多两个数字,所以,可以发现,解决方法与climb stairs类似,使用动态规划,假设数组dp[i]表示从头到字符串的第i位,一共有多少种解码方法的话,如果字符串的第i-1位和第i位能组成一个10到26的数字,说明我们是在第i-2位的解码方法上继续解码(dp[i] += dp[i-2])。如果字符串的第i-1位和第i位不能组成有效二位数字,而且第i位不是0的话,说明我们是在第i-1位的解码方法上继续解码(dp[i] += dp[i - 1])。所以,如果两个条件都符合,则dp[i]=dp[i -1]+dp[i + 2],否则dp[i] = dp[i - 1]。
class Solution {//5ms
public int numDecodings(String s) {
if(s.length() ==0) return s.length();
int[] dp = new int[s.length() + 1];
dp[0] = 1;//初始化第一种解码方式
dp[1] = s.charAt(0) == '0' ? 0 : 1;//如果第一位是0,则无法解码
for(int i = 2;i <= s.length();i ++){
// 如果字符串的第i-2位和第i-1位能组成一个10到26的数字,说明我们可以在第i-2位的解码方法上继续解码,有两位数字
if(Integer.parseInt(s.substring(i - 2,i)) <= 26 && Integer.parseInt(s.substring(i - 2,i)) >= 10){
dp[i] += dp[i - 2];
}
// 如果字符串的第i-2位和第i-1位不能组成有效二位数字,在第i-1位的解码方法上继续解码,只有一位数字
if(Integer.parseInt(s.substring(i-1, i)) != 0){
dp[i] += dp[i - 1];
}
}
return dp[s.length()];
}
}
另一种解法:
class Solution { //2ms
public int numDecodings(String s) {
if(s == null || s.length() == 0 || (s.length() > 1 && s.charAt(0) == '0')) return 0;
int[] dp = new int[s.length() + 1];
dp[0] = 1;//初始化第一种解码方式
for (int i = 1;i < dp.length ;i ++ ) {
dp[i] = (s.charAt(i - 1) == '0') ? 0 : dp[i - 1];//在第i-1位的解码方法上继续解码
if(i > 1 && (s.charAt(i - 2) == '1' || (s.charAt(i - 2) == '2') && s.charAt(i - 1) <= '6')){//如果字符串的第i-1位和第i位能组成一个10到26的数字,说明我们可以在第i-2位的解码方法上继续解码
dp[i] += dp[i - 2];
}
}
return dp[s.length()];
}
}
② 在discuss中看到的,使用两个变量,分别记录一位数和两位数的情况。
class Solution {//1ms
public int numDecodings(String s){
if (s.length() == 0) return 0;
int preFir = 1;
int preSec = 1;
char[] schar = s.toCharArray();
for (int i = 0;i < schar.length;i ++){
int way = 0;
int val1 = schar[i] - '0';
if (val1 >= 1 && val1 <= 9){//1~9之间
way += preFir;
}
if (i >= 1){//10~26之间
int val2 = (schar[i - 1] - '0') * 10 + val1;
if (val2 >= 10 && val2 <= 26){
way += preSec;
}
}
preSec = preFir;
preFir = way;
}
return preFir;
}
}