难度:中等
一条包含字母 A-Z
的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:
输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。
示例 2:
输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
题目分析:
做完之后才知道,这题为啥通过率这么低。这个0是真的恶心。1.当0和前面的数组合大于26时就无效返回0;2.当连续出现0的时候无效返回0;3.当0和出现在首位的时候无效,返回0.这题显然用DP。
1.状态转换方程是:1)当s[i] == 0的时候:
f[i] = f[i-2] (因为0和前面一个数字进行了绑定)
2)当s[i] != 0的时候:
f[i] = f[i-1] + f[i-2] (在当前值和前面一个值组合小于等于26的时候);
f[i] = f[i-1] (当前值和前面一个值组合大于26时)
2.数据结构选择一维数组
3.初始化,注意0可能出现在第一和第二位。当没有0出现时,f[0] = 1,f[1]和f[0]的组合大于等于26时,f[1] = 1,否则 f[1] =2;
4,遍历填表。很关键的是要分析0的情况(具体见代码)
参考代码:
class Solution {
public:
int numDecodings(string s) {
if (s.empty())
return s.size();
vector<int> f;
f.resize(s.size());
//首位为0,返回0;否则初始化
if (s[0] == '0')
return 0;
else
f[0] = 1;
//必须要判断,否则如果只有一位,下面的s[1]会越界
if (s.size() == 1)
return 1;
//第二位不为0,如果和s[0]组合小于等于26,f[1] = 2,否则f[1] = 1
//第二位为0,如果前面那位大于2,就是无效数组,返回0
if (s[1] != '0' && (s[0] - '0') * 10 + s[1] - '0' <= 26)
f[1] = 2;
else if (s[1] == '0' && !(s[0] == '1' || s[0] == '2'))
return 0;
else
f[1] = 1;
int temp = 0;
//从第三个数开始遍历,大致分三种情况
for (int i = 2; i < s.size(); i++)
{
//当前值为0,前面的值为1或者2,有效,当前的总数等于前面第二位
if (s[i] == '0' && (s[i - 1] == '1' || s[i - 1] == '2'))
f[i] = f[i - 2];
//当前值为0,前面的值不为1或者2,无效
else if (s[i] == '0' && !(s[i - 1] == '1' || s[i - 1] == '2'))
return 0;
//当前值不为0的情况,需要判断前面那个值为不为0
else if (s[i] > '0' && s[i] <= '9')
{
//前面的值不为0,正常判断
if (s[i - 1] != '0')
{
temp = (s[i - 1] - '0') * 10 + s[i] - '0';
if (temp <= 26)
f[i] = f[i - 1] + f[i - 2];
else
f[i] = f[i - 1];
}
else{//前面的值为0,当前的总数等于前面第二位
f[i] = f[i - 2];
}
}
}
return f[s.size() - 1];
}
};
参考代码:(上面那种情况分的太复杂了,看看这个)
class Solution {
public:
int numDecodings(string s) {
//如果空字符串或者开局为0,那不好意思直接返回0(失效)
if (s.empty() || s[0] == '0')
return 0;
//只有一个字符的话就直接返回1吧
if (s.size() == 1)
return 1;
vector<int> f(s.size() + 1, 0);//这里多申请一个单位内存,后边有用
s = "0" + s;//为了方便计算,最前面加个“0”字符
//初始化一下,前面两个字符对应的数为1
f[0] = 1;
f[1] = 1;
for (int i = 2; i < s.size(); i++) //从第三个字符开始(加“0”后)
{
//先计算一波当前位置和前面一位组成的数
int temp = (s[i - 1] - '0') * 10 + s[i] - '0';
//先考虑当前字符为“0”(0字符贼坑)
if (s[i] == '0')
{
//如果前一个字符也为“0”或者和前面字符不能组成10,20(都是无效情况)
if (s[i - 1] == '0' || temp > 26)
return 0;
else
//或者就等于f[i - 2],如果不是这么操作的话,遇到110这种情况就会算错
f[i] = f[i - 2];
}
else{//当前字符不是“0”字符
//如果前一个字符等于“0”,或者两个字符组合大于26,就等于前面一个就行
if (s[i - 1] == '0' || temp > 26)
f[i] = f[i - 1];
else//如果组合数是在(10,26]之间,那么相加
f[i] = f[i - 1] + f[i - 2];
}
}
return f[s.size()-1];
}
};