91. 解码方法
一条包含字母 A-Z 的消息通过以下方式进行了编码:
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:
输入: “12”
输出: 2
解释: 它可以解码为 “AB”(1 2)或者 “L”(12)。
示例 2:
输入: “226”
输出: 3
解释: 它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。
状态
- dp[i]: 到位置i为止的编码数
状态转移:
- 如果charArray[i] != ‘0’ : dp[i] = dp[i-1] , 可以延续上一个, dp[i-1]编码 + 单数编码
- 如果 10 <= num = 10 * (charArray[i-1] - ‘0’) + (charArray[i] - ‘0’) <= 26, 说明这个编码和0 - i-2的编码可以组合;dp[i - 2]编码 + 双数编码
- 两种分类即:dp[i] = dp[i-1] + dp[i-2]; dp[i] = (dp[i-1]编码 + 单数编码) + (dp[i - 2]编码 + 双数编码)
初始化
- dp[0] = 1
出错:
- 因为dp[i] = dp[i-1] + dp[i-2]; 所以要将i = 1单独拎出来,要不然会越界,我的错误代码:
if(i == 1) {
dp[i] = dp[i-1] + 1;
}
分析原因:
- 当 i = 1 时,charArray[1] = ‘0’ ,所以dp[1] = 0;
- 进入if 判断,dp[1] = dp[0] + 1 = 1 + 1 = 2; 逻辑应该是 dp[i] = dp[i-2] + dp[i-1], 逻辑没有理清楚,而由于这里i == 1会越界,所以才把 i == 1单独拎出来
- 即只有两个元素时,1?,?如果是0,则res= 1,如果2<=?<=9, 则res = 2;
- 转换为代码:先判断charArray[1]是否为0,如果不为0,由dp[i-1]转移过来,否则dp[1]是初始化0,即从这里会中断;再去判断,是否和前面的 i - 1组成数字;
- 而正确答案是1
正确代码:
if(i == 1) {
dp[i]++;
}
再来几个实例;
String s = “103”; res = 1, dp = [1,1,1];
- 所以if(i == 1)判断不是为了当len==2,而是针对当指针i走到1的位置时的判断。
class Solution {
public int numDecodings(String s) {
int len = s.length();
if(len == 0) return 0;
int[] dp = new int[len];
char[] charArray = s.toCharArray();
if(charArray[0] == '0') return 0;
dp[0] = 1;
for(int i = 1; i < len; i++) {
if(charArray[i] != '0') {
dp[i] = dp[i-1];
}
int num = 10 * (charArray[i-1] - '0') + (charArray[i] - '0');
if(num <= 26 && (num >= 10)) {
if(i == 1) {
dp[i]++;
}else {
dp[i] += dp[i-2];
}
}
}
return dp[len - 1];
}
}