解码方法 II
难度:
标签:
题目描述
代码结果
运行时间: 157 ms, 内存: 20.2 MB
/*
* 解题思路:
* 1. 使用 Java Stream API 处理字符串,利用 stream 迭代处理字符和子字符串。
* 2. 通过映射和归约操作计算总解码方法数。
*/
import java.util.stream.IntStream;
public class DecodeWaysStream {
private static final int MOD = 1000000007;
public int numDecodings(String s) {
long[] dp = new long[s.length() + 1];
dp[0] = 1;
dp[1] = s.charAt(0) == '*' ? 9 : (s.charAt(0) == '0' ? 0 : 1);
IntStream.range(2, s.length() + 1).forEach(i -> {
char c1 = s.charAt(i - 1);
char c2 = s.charAt(i - 2);
if (c1 == '*') {
dp[i] += 9 * dp[i - 1];
} else if (c1 != '0') {
dp[i] += dp[i - 1];
}
if (c2 == '*') {
if (c1 == '*') {
dp[i] += 15 * dp[i - 2];
} else if (c1 <= '6') {
dp[i] += 2 * dp[i - 2];
} else {
dp[i] += dp[i - 2];
}
} else if (c2 == '1' || c2 == '2') {
if (c1 == '*') {
dp[i] += (c2 == '1' ? 9 : 6) * dp[i - 2];
} else if ((c2 - '0') * 10 + (c1 - '0') <= 26) {
dp[i] += dp[i - 2];
}
}
dp[i] %= MOD;
});
return (int) dp[s.length()];
}
}
解释
方法:
这个题解使用动态规划的思路来解决解码方法的问题。定义 dp[i] 表示字符串的前 i 个字符有多少种解码方法。对于第 i 个字符,需要根据其是数字还是 '*',以及前一个字符的情况来更新 dp[i]。具体来说:
1. 如果当前字符是 '0',那么它只能和前一个字符一起解码,并且前一个字符必须是 '1' 或 '2',否则无法解码。
2. 如果当前字符是 '1'~'6',那么它可以单独解码,也可以和前一个字符一起解码(如果前一个字符是 '1' 或 '2')。
3. 如果当前字符是 '7'~'9',那么它只能单独解码,或者和前一个字符一起解码(如果前一个字符是 '1')。
4. 如果当前字符是 '*',那么它可以表示 '1'~'9' 中的任意数字,需要根据前一个字符是 '1'、'2' 还是其他数字来更新 dp[i]。
最终的答案即为 dp[n-1],也就是整个字符串的解码方法数目。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在动态规划解法中,为什么要对结果取模10^9+7?这个数字有什么特殊的意义吗?
▷🦆
题解中提到如果当前字符是'0',只能和前一个字符一起解码。如果前一个字符也是'*',该如何处理?
▷🦆
为什么当当前字符为'*'且前一个字符为'1'或'2'时,有不同的解码方式数量计算?具体是如何计算这些解码方式的?
▷🦆
题解中提到,如果当前字符是'1'~'6',可以单独解码或和前一个字符一起解码。如果前一个字符是'*',为何解码方式数是当前dp[i-1]加上dp[i-2]的两倍?
▷相关问题
解码方法
一条包含字母 A-Z
的消息通过以下映射进行了 编码 :
'A' -> "1" 'B' -> "2" ... 'Z' -> "26"
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106"
可以映射为:
"AAJF"
,将消息分组为(1 1 10 6)
"KJF"
,将消息分组为(11 10 6)
注意,消息不能分组为 (1 11 06)
,因为 "06"
不能映射为 "F"
,这是由于 "6"
和 "06"
在映射中并不等价。
给你一个只含数字的 非空 字符串 s
,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 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 = "06" 输出:0 解释:"06" 无法映射到 "F" ,因为存在前导零("6" 和 "06" 并不等价)。
提示:
1 <= s.length <= 100
s
只包含数字,并且可能包含前导零。