leetcode原题链接: 解码方法
ms-hot目录: ms-hot目录
上一篇 :ms-hot28 合并两个有序数组
下一篇:二叉树的中序遍历
题目描述
一条包含字母 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" 并不等价)。
给你一个只含数字的 非空 字符串 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
只包含数字,并且可能包含前导零。
解题方法:动态规划DP。
-
问题定义: dp[i]表示以第i个字符结尾的解码方法数,则申请n+1大小的dp数组。
-
初始化:
dp[0]=1
如果s[1] >= '1' and s1<='9' ==> dp[1]=1; 否则dp[1]=0
- 状态转移方程:考虑点是s[i]是单独解码,还是s[i-1], s[i]两个字符一起解码。
1)如果s[i]单独解码:则dp[i+1] = dp[i+1] + dp[i] --注意最开始的时候dp[i+1]默认值为0;
2)如果s[i]和s[i-1]一起解码,则需要判断s[i-1]和s[i]组成的数组num是否满足 1 <= num <= 26这个条件,如果满足这个条件,则dp[i+1] = dp[i+1] + dp[i-1]。
- 返回解:最后求到的dp[n]即为以最后一个字符结尾的解码数,即为问题的解。
C++代码
cpp
#include <iostream>
#include <string>
#include <vector>
class Solution {
public:
int numDecodings(string s) {
int n = s.size();
if (n == 0) {
return 0;
}
vector<int> dp(n + 1, 0); //dp[i]表示以第i个字符结尾的字符串对应的解码方法数
dp[0] = 1; //初始化:空字符串解码数为1(即解码出一个空字符串)
dp[1] = (s[0] >= '1' && s[0] <= '9') ? 1 : 0;
for (int i = 1; i < n; i++) {
int cur = s[i] - '0';
int pre = s[i - 1] - '0';
if (cur >= 1) { //考虑s[i]单独解码
dp[i + 1] += dp[i];
}
if (pre == 1 ||(pre == 2 && cur <= 6) ) { //考虑s[i]和s[i-1]一起解码
dp[i + 1] += dp[i - 1];
}
}
return dp[n];
}
};