解码方法
涉及知识:动态规划、分类讨论
分析:
首先从简单的情形进行分析,找出大概的状态转移方程,在逐步进行分类讨论。
假设给一个数串,". . . . . . 1258654326014 . . . . . .",dp[k] 表示 k 位数字的解码方法的总数,由于数字 1 - 26 分别表示字母 A - Z,数字为个位数或者两位数。则有两种情况:
- 第 k 位一位数字表示一个字母:方案数为dp[k - 1],
- 第(k - 1)和第 k 位两位数字表示一个字母:方案数为dp[k - 2]
因此,状态转移方程的一般形式为:dp[k] = dp[k - 1] + dp[k - 2]
但是,由于两种情况不一定可以同时取到,因此需要进行分类讨论。
- 当第 k - 1 位不为 0 的时候:
- 如果第 k 位不为 0,则第 k 位可以通过一位数字表示一个字母。
- 当两位数字组合起来大于等于 10 小于等于 26 的时候,则可以通过两位数字的组合来表示一个字母。
- 当第 k - 1 位为 0 的时候:
- 如果第 k 位不为 0,则第 k 位可以通过一位数字表示一个字母。
- 否则,存在连续两位同时为零,方案数为 0,直接返回 0
代码:
/*
* @lc app=leetcode.cn id=91 lang=java
*
* [91] 解码方法
*/
class Solution {
public int numDecodings(String s) {
int[] dp = new int[s.length() + 5];
dp[0] = 1;
dp[1] = 1;
//特殊判断,首位为 0,无解
if(s.length() == 0 || s.charAt(0) == '0'){
return 0;
}
int i = 0;
int tmp1 = 0;
int tmp2 = 0;
for(int j = 1; j < s.length(); ++j){
i = j + 1;
dp[i] = 0;
//j - 1 位不为 0
if(s.charAt(j - 1) != '0'){
//j - 1 位为 0,j 位不为 0
if(s.charAt(j) != '0'){
dp[i] += dp[i - 1];
}
tmp1 = s.charAt(j - 1) - '0';
tmp2 = s.charAt(j) - '0';
if((tmp1 == 1 || tmp1 == 2) && tmp1 * 10 + tmp2 <= 26 && tmp1 * 10 + tmp2 >= 10){
dp[i] += dp[i - 2];
}
} else if(s.charAt(j) != '0'){ //j - 1 位为 0,j 位不为 0
dp[i] += dp[i - 1];
} else { //连续两个 0
return 0;
}
}
return dp[s.length()];
}
}