一条包含字母 A-Z 的消息通过以下的方式进行了编码:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
除了上述的条件以外,现在加密字符串可以包含字符 * 了,字符 * 可以被当做 1 到 9 当中的任意一个数字。
给定一条包含数字和字符 * 的加密信息,请确定解码方法的总数。
同时,由于结果值可能会相当的大,所以你应当对结果 10^9 + 7取模
取模。(翻译者标注:此处取模主要是为了防止溢出) 样例
输入: "*" 输出: 9 解释: 加密的信息可以被解密为: "A", "B", "C", "D", "E", "F", "G", "H", "I"。
输入: "1*" 输出: 9 + 9 = 18(翻译者标注:这里 1* 可以分解为 1,* 或者当做 1* 整体来处理,所以结果是 9 + 9 = 18)。
注意
输入的字符串长度范围是 [1, 10^5]。
输入的字符串只会包含字符 * 和 数字 0 - 9。
题解
1 动态规划最重要的就是找出转移方程,dp[i] 表示字符串长度为i的s最大解密方式,可以发现A-Z 是从1-26的,所以dp[i] 可以从dp[i-2]和dp[i-1]来获得。
时间复杂度O(n)空间复杂度O(n)
/**
* @param {string} s
* @return {number}
*/
export default (s) => {
let dp = new Array(s.length + 1).fill(0);
dp[0] = 1;
if (s.charAt(0) == "0") {
return 0;
}
if (s.charAt(0) === "*") {
dp[1] = 9;
} else {
dp[1] = 1;
}
for (let i = 2; i <= s.length; i++) {
// // 最后一个字母
// const firstLetter = s.charAt(i - 1);
// // 倒数第二个字母
// const secondLetter = s.charAt(i - 2);
if (s.charAt(i - 1) === "*") {
dp[i] = 9 * dp[i - 1];
} else if (+s.charAt(i - 1) < 10 && +s.charAt(i - 1) > 0) {
dp[i] = dp[i - 1];
}
if (s.charAt(i - 1) === "*") {
if (s.charAt(i - 2) === "*") {
dp[i] += 15 * dp[i - 2];
} else {
if (s.charAt(i - 2) === "1") {
dp[i] += 9 * dp[i - 2];
} else if (s.charAt(i - 2) === "2") {
dp[i] += 6 * dp[i - 2];
}
}
} else if (+s.charAt(i - 1) < 7) {
if (s.charAt(i - 2) === "*") {
dp[i] += 2 * dp[i - 2];
} else {
if (s.charAt(i - 2) === "1") {
dp[i] += dp[i - 2];
} else if (s.charAt(i - 2) === "2") {
dp[i] += dp[i - 2];
}
}
} else if (+s.charAt(i - 1) >= 7) {
if (s.charAt(i - 2) === "*") {
dp[i] += dp[i - 2];
} else {
if (s.charAt(i - 2) === "1") {
dp[i] += dp[i - 2];
}
}
}
dp[i] = dp[i] % 1000000007;
}
return dp[s.length];
};