91. 解码方法
题目链接: 91. 解码方法
题目叙述: 一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
“1” -> ‘A’
“2” -> ‘B’
…
“25” -> ‘Y’
“26” -> ‘Z’
然而,在解码已编码的消息时,你意识到有许多不同的方式来解码,因为有些编码被包含在其它编码当中(“2” 和 “5” 与 “25”)。
例如,11106
可以映射为:
"AAJF"
,将消息分组为 (1, 1, 10, 6)
"KJF"
,将消息分组为 (11, 10, 6)
消息不能分组为 (1, 11, 06) ,因为 “06” 不是一个合法编码(只有 “6” 是合法的)。
注意,可能存在无法解码的字符串。
给你一个只含数字的 非空 字符串 s
,请计算并返回 解码 方法的 总数 。如果没有合法的方式解码整个字符串,返回 0
。
题目数据保证答案肯定是一个 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
只包含数字,并且可能包含前导零。
💦 前提注意: 这道题的s
是一个非空字符串,而不是数组,所以计算时应减去'0'
解题思路:
- 状态表示
dp[i]表示:以i
位置为结尾时,所有解码方法的总数 - 状态转移方程
根据最近的一步,划分问题
其中a
表示s[i]
位置的数,b
表示s[i-1]
位置的数
dp[i] = dp[i-1] + dp[i-2] - 初始化
保证填表时不越界
以0
位置结尾时说明此时只解码了一个字符
以1
位置结尾时说明此时解码了两个字符
- 填表顺序
从左向右 - 返回值
dp[n-1]
代码实现:
class Solution {
public:
int numDecodings(string s) {
//创建dp表
//初始化
//填表
//返回值
int n = s.size();
vector<int> dp(n);
dp[0] = s[0] != '0';
//处理边界条件
if (n == 1) return dp[0];
if (s[0] != '0' && s[1] != '0') dp[1] += 1;//第一个位置能单独解码,并且第二个位置也能单独解码
int t = (s[0] - '0') * 10 + s[1] - '0';//前两个位置所表示的数
if (t >= 10 && t <= 26) dp[1] += 1;
for (int i = 2; i < n; i++)
{
if (s[i] != '0') dp[i] += dp[i - 1];//处理单独解码的情况
int t = (s[i - 1] - '0') * 10 + s[i] - '0';//第二种情况所对应的数
if (t >= 10 && t <= 26) dp[i] += dp[i - 2];
}
return dp[n - 1];
}
细节优化:
处理边界问题以及初始化问题的技巧
- 我们可以开一个比旧的表多1个的新的
dp
表,使得旧dp
表下标为0
的位置,映射到新的dp
表下标为1
的位置,旧的下标为1
的位置映射到新的下标为2
的位置…依次类推。
- 这样以来
dp[i]
就可以表示为以第i
个字符为终点的解码方法的个数。所以就只需要初始化第1的字符即可。 - 这里有个小细节,我们在初始化
dp[0]
这个虚拟节点时要将它初始化成1
,比如只有两个字符我们要判断时 ,第二个字符单独解码时的方法数为1
,第二个字符与第一个字符共同解码时的方法总数应该为2
,dp[2] = dp[1] + dp[0]
,我们可以将dp[0]
给反推出来,所以dp[0]
应该初始化为1
代码实现:
class Solution {
public:
int numDecodings(string s) {
//创建dp表
//初始化
//填表
//返回值
int n = s.size();
//创建dp表
vector<int> dp(n+1);
dp[0] = 1;
dp[1] = s[0] != '0';
for(int i = 2;i <= n;i++)
{
if(s[i-1] != '0') dp[i]+=dp[i-1];
int b = 10*(s[i-2]-'0') + (s[i -1] - '0');
if(b>=10 && b <= 26) dp[i]+=dp[i- 2];
}
return dp[n];
}
};