「这是我参与11月更文挑战的第29天,活动详情查看:2021最后一次更文挑战」。
题目
链接:leetcode-cn.com/problems/de…
一条包含字母 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 = "0" 输出: 0 解释: 没有字符映射到以 0 开头的数字。 含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。 由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。
示例 4:
输入: s = "06"
输出: 0
解释: "06" 不能映射到 "F" ,因为字符串含有前导 0("6" 和 "06" 在映射中并不等价)。
提示:
1 <= s.length <= 100s只包含数字,并且可能包含前导零。
解题思路
思路1,动态规划
-
思路
'A' -> 1
'B' -> 2
...
'Z' -> 26- 由示例和题中转码公式可知
- 数字转换为字母,最大支持26,最小支持1:
- 数字组合最大为两位数,且小于27,大于0
- 当为1位数时,形如X
- 0
- 首字母,返回0
- 非首字母,跳过,此处组合为0
- 非0
- 本身为1个组合
- 转移方程
- s[i-1] != 0 && dp[i] = dp[i-1] + dp[i]
- 0
- 当为2位数时,形如nX
- 1X
- 10、11、12...19 所以X可以是任意值
- 转移方程
- s[i-2] == 1 && dp[i] = dp[i] + dp[i-2]
- 2X
- 20、21、21...26 所以 X < 7
- 转移方程
- s[i-2] == 2 && s[i-1] < 7 && dp[i] = dp[i] + dp[i-2]
- 3X、4X、5X、6X、7X、8X、9X
- 30、40、50、60、70、80、90
- 所以 n > 3 时,X只能为0,可以直接跳过
- 因此可以归纳到第一种情况中去,为1位数:形如X,直接跳过
- 1X
- 当为1位数时,形如X
- 数字为 0 时,无法解码
- 又根据题意,首数字必须可以解码,如果数字第一位为0,则解码总数为0,视为无效
- 数字组合最大为两位数,且小于27,大于0
- 数字转换为字母,最大支持26,最小支持1:
- 由示例和题中转码公式可知
/**
* @param {string} s
* @return {number}
*/
var numDecodings = function(s) {
if(s[0] == 0){
return 0;
}
let n = s.length;
let dp = new Array(n+1).fill(0);
dp[0] = dp[1] = 1;
for(let i = 2;i <= n;i++){
if(s[i-1] != 0){
dp[i] += dp[i-1];
}
if((s[i-2] == 1) || (s[i-2] == 2 && s[i-1] <= 6)){
dp[i] += dp[i-2];
}
}
return dp[n];
};
思路2,递归
- 通过索引 穷举 i-2和i-1的所有可能组合情况
/**
* @param {string} s
* @return {number}
*/
var numDecodings = function(s) {
if(s[0] == 0){
return 0;
}
let n = s.length;
let helper = (start) => {
if(start == n){
return 1;
}
if(s[start] == 0){
return 0;
}
let odd = helper(start+1);
let even = 0;
if(start < n - 1){
let ten = s[start];
let one = s[start+1];
if((ten+''+one) < 27){
even = helper(start+2);
}
}
return odd + even;
}
return helper(0);
};
思路3,递归 + 备忘录
/**
* @param {string} s
* @return {number}
*/
var numDecodings = function(s) {
if(s[0] == 0){
return 0;
}
let n = s.length;
let memo = new Map();
let helper = (start) => {
if(start == n){
return 1;
}
if(s[start] == 0){
return 0;
}
let memoVal = memo.get(start);
if(memoVal){
return memoVal;
}
let odd = helper(start+1,memo);
let even = 0;
if(start < n - 1){
let ten = s[start];
let one = s[start+1];
if((ten+''+one) < 27){
even = helper(start+2,memo);
}
}
let res = odd + even;
memo.set(start,res);
return res;
}
return helper(0,memo);
};