题目
一条包含字母 A-Z 的消息通过以下方式进行了编码:
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
注意:可能存在不能解码的情况,如’00’
示例
示例 1:
输入: “12”
输出: 2
解释: 它可以解码为 “AB”(1 2)或者 “L”(12)。
示例 2:
输入: “226”
输出: 3
解释: 它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。
思路
递推
我们发现dp[n]的解码方法数只与dp[n-1]和dp[n-2]有关(dp[i]代表到第i位为止的解码种数)
1、当s.charAt(i)=='0’时,说明第i位不能单独解码,所以dp[i]=0,否则dp[i]=dp[i-1]
2、当i-1位与i位组成的数在1~26,说明[i-1,i]可以组成合法的编码,所以dp[i]=dp[i]+dp[i-2],否则不改变
(注意:我写的步骤是有顺序的,不然公式就要发生改变,但思路理解,怎么改你都应该会写)
(其实递归也是能做的,但超时了,所以就不放上来了)
看过上面过程,其实我们能发现我们只需要保存dp[i-2],dp[i-1],dp[i]的值,所以我们只需要三个变量进行递推即可。
代码
public class problem91 {
/*
* 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 …… 'Z' -> 26
*
* 给定一个只包含数字的非空字符串,请计算解码方法的总数。
*
* 如12可解析为1、2或12
*
*/
public int numDecodings(String s) {
// 特判
if (s.length() == 0)
return 0;
if (s.charAt(0) == '0')
return 0;
if (s.length() == 1)
return 1;
//// 保存dp[n - 2], dp[n - 1], dp[n](dp[i]表示到第i个字符为止的解码方式)
int[] dp = { 0, 1, 1 };
for (int i = 1; i < s.length(); i++) {
dp[0] = dp[1];
dp[1] = dp[2];
if (s.charAt(i) == '0')
dp[2] = 0;
//判断第n-1和第n位是否会组成一个正确的编码
int tmp = (s.charAt(i - 1) - '0') * 10 + s.charAt(i) - '0';
if (tmp > 9 && tmp < 27)
dp[2] = dp[2] + dp[0];
// 出现'00'时,提前返回,节约时间
else if (tmp == 0)
return 0;
}
return dp[2];
}
public static void main(String[] args) {
problem91 pro = new problem91();
System.out.println(pro.numDecodings("12"));
}
}