题目
链接:https://leetcode-cn.com/problems/decode-ways
一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
题目数据保证答案肯定是一个 32 位的整数。
示例 1:
输入:s = "12"
输出:2
解释:它可以解码为 "AB"(1 2)或者 "L"(12)。
示例 2:
输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
示例 3:
输入:s = "0"
输出:0
示例 4:
输入:s = "1"
输出:1
示例 5:
输入:s = "2"
输出:1
提示:
1 <= s.length <= 100
s 只包含数字,并且可能包含前导零。
动态规化
分析第一种情况子串中不包含0
假设 s = 226
s
子串2
长度为1
解码方式为1
种:2
s
子串22
长度为2
解码方式为2
种2,2 、 22
s
子串226
长度为2
解码方式为3
种2,2,6、22,6、2,26
设dp[i]
代表长度为i
的字符串有几种解码方式,dp[1] = 1
每当再字符串子串后面增加一个字符,比如在22
后面增加6
,6单独看新子串的解码方式有2种:2,2,6、22,6,如果新增字符6与前一个字符相结合在[10,26]范围内则解码方式又增加一种:2,26。所以状态转移方程为:
d
p
[
i
]
+
=
d
p
[
i
−
1
]
dp[i] += dp[i-1]
dp[i]+=dp[i−1]
如果 新增字符与最后一个字符组合后符合条件
d
p
[
i
]
+
=
d
p
[
i
−
2
]
dp[i] += dp[i-2]
dp[i]+=dp[i−2]
以上不含0的情况,如果字符串s最后一位为0比如说10
、20
这种情况,那么0只能和前一位组合起来看所以状态转移方程为
d
p
[
i
]
+
=
d
p
[
i
−
2
]
dp[i] += dp[i-2]
dp[i]+=dp[i−2]
所以dp[0]要初始化为1。
综上状态转移方程为:
s最后一个字母不为0则:
d
p
[
i
]
+
=
d
p
[
i
−
1
]
dp[i] += dp[i-1]
dp[i]+=dp[i−1]
如果 新增字符与最后一个字符组合后符合条件
d
p
[
i
]
+
=
d
p
[
i
−
2
]
dp[i] += dp[i-2]
dp[i]+=dp[i−2]
代码如下:
class Solution {
public int numDecodings(String s) {
// 如果首字母为'0'则不和任何字母对应,之间返回0
if (s == null || s.length() == 0 || s.charAt(0) == '0') return 0;
int n = s.length();
// 状态设置: dp[i] 表示长度为i的字符串的解码方式的次数
int[] dp = new int[n + 1];
dp[0] = 1; // 考虑10这种情况dp[2] += dp[2-2]
dp[1] = 1;// 长度为1的字符串解码方式为一种也就是s[0]
for (int i = 2; i <= n; i++) {
if (s.charAt(i-1) != '0') {// 如果字符串s最后一个字符不为0,那么可以单独拿出来 比如 11--> 1,1
dp[i] += dp[i-1];
}
int num = Integer.valueOf(s.substring(i-2,i));
if (num >= 10 && num <= 26) {
dp[i] += dp[i-2];
}
}
System.out.println(Arrays.toString(dp));
return dp[n];
}
}