一条包含字母 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.length <= 100s只包含数字,并且可能包含前导零。
示例 1:
输入:s = "12"
输出:2
解释:它可以解码为 "AB"(1 2)或者 "L"(12)。
示例 2:
输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
题解:
/**
* @description: 递归回溯 TC:O(2^n) SC:O(1)
* @author: JunLiangWang
* @param {*} s 给定字符串S
* @return {*}
*/
function recursionBackTracking(s){
/***
* 该方案使用递归回溯的方式,逐个以1个/2个字符
* 组成解码方法递归字符串S。
*/
// 记录解码方式数量
let count=0;
/**
* @description: 递归
* @author: JunLiangWang
* @param {*} index 当前递归到字符串S索引位置
* @return {*}
*/
function cursion(index){
// 如果索引超出s长度,证明已遍历完字符串所
// 有字符满足解码要求,此时解码方式+1
if(index>=s.length){
count++;
return ;
}
// 如果当前字符等于0,无论是以该字符单独解码
// 还是以它作为首位,与其他字符组合解码都是
// 无法解码的,例如:'0'或'02'。此时结束递归
if(s[index]!=0){
// 以该字符单独解码的方式,继续递归。
cursion(index+1)
// 如果该字符满足与下一个字符组合解码
if(s[index+1]!=undefined&&s[index]*10+s[index+1]*1<=26)
// 则与下一个字符组合解码,继续递归。
cursion(index+2)
}
}
// 执行递归
cursion(0)
// 返回结果
return count;
}
/**
* @description: 动态规划 TC:O(n) SC:O(n)
* @author: JunLiangWang
* @param {*} s 给定字符串s
* @return {*}
*/
function DP(s){
/**
* 该方案使用动态规划的方式,试想字符串为以下:
*
* s = '1' n = 1
* '11' 2
* '111' 3
* '1111' 5
* '11111' 8
*
* 大家是否看出了规律,当前字符串的解码的解码方式
* 等于上两个解码方式之和,但这并没有涵盖字符串S的
* 所有情况,例如下一个:
*
* s = '1' n = 1
* '11' 2
* '110' 1
* '1101' 1
* '11011' 2
*
* 当遇到0时,该字符串的解码方式不再等于上两个之和了
* 而是等于前两个的解码方式,这是由于0必须和前一个字符
* 组合,因此他们便成为了一个整体,其解码方式等同于删除
* 它们两个后的解码方式,这也并未涵盖字符串s的所有情况
* 例如下一个:
*
* s = '1' n = 1
* '13' 2
* '132' 2
* '1321' 4
* '13211' 6
* 当遇到字符两者组合大于26时,此时无法组合成有效的解码,
* 因此当前字符就只能作为单独字符解码,其解码方式就等同于
* 删除它本身
*
* 以上则涵盖了所有情况,我们可以使用动态规划的方式,记录
* 上一/两字符解码方式情况,再根据当前字符比较计算得出当前
* 字符的解码方式。
*/
// 如果首个字符为0,则该字符串无法解码,直接返回0
if(s[0]==='0')return 0
// 初始化动态规划数组,长度加一是由于第二个字符并没有
// 上两个字符,因此通过加一长度来模拟
let DPArray=new Array(s.length+1)
// 初始化第0个字符的解码方式为1
DPArray[0]=1;
// 初始化第1个字符的解码方式为1
DPArray[1]=1
// 从第二个字符开始遍历字符串S
for(let i=1;i<s.length;i++){
// 获取上一个字符的情况
let lastNum=s[i-1]*1
// 如果当前字符为0
if(s[i]==='0')
{
// 由于0必须和前一个字符组合,
// 因此他们便成为了一个整体,
// 如果两字符组合大于26时,
// 则无法组合成有效的解码,
// 直接返回0
if(lastNum>0&&lastNum<3)
// 否则其解码方式等同于删除
// 它们两个后的解码方式
DPArray[i+1]=DPArray[i-1]
else return 0
}
// 如果当前字符不为0
else
{
// 当两字符组合大于26或上一个字符等于0,
// 此时无法组合成有效的解码,因此当前字
// 符就只能作为单独字符解码,其解码数量
// 等于删除它本身后的解码数量
if(lastNum==0||lastNum*10+s[i]*1>26)
DPArray[i+1]=DPArray[i]
// 否则,字符串的解码的解码方式
// 等于上两个解码方式之和
else
DPArray[i+1]=DPArray[i]+DPArray[i-1]
}
}
// 返回结果
return DPArray[s.length]
}
来源:力扣(LeetCode)
🚀广告
最近开了一个新专栏《HTTP完全注解》,准备全面介绍下HTTP/0.9到HTTP/2.0,但数据有些惨淡😭,有点失落。如果你想要全面学习了解HTTP,不妨看看,绝对会给你惊喜!