题目来源:https://leetcode-cn.com/problems/decode-ways/
题目描述
一条包含字母 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) 。
解法
注意动态规划中dp[i]的含义:这里代表以s[i]结尾的解码方法的总数
这里的思路:
- 首先对特殊情况进行讨论,如果 s . s i z e ( ) = = 0 s.size()==0 s.size()==0 或者 s [ 0 ] = = ′ 0 ′ s[0]=='0' s[0]==′0′的情况 直接返回0(0不是合法)
- 其次对
s
[
i
]
s[i]
s[i]进行判断,推导状态转移公式
即 如果 s [ i ] = = ′ 0 ′ s[i]=='0' s[i]==′0′那么需要判断 s [ i − 1 ] = = ′ 1 ′ ∣ ∣ s [ i − 1 ] = = ′ 2 ′ s[i - 1] == '1' || s[i - 1] == '2' s[i−1]==′1′∣∣s[i−1]==′2′才能组成合法字符,此时 d p [ i ] = d p [ i − 2 ] dp[i]=dp[i-2] dp[i]=dp[i−2]此外 s [ i − 1 ] s[i-1] s[i−1]的情况不能和 ′ 0 ′ '0' ′0′组成合法字符因此 直接返回 0 0 0
如果 s [ i ] s[i] s[i]在1~6之间 则如果 s [ i − 1 ] = = ′ 1 ′ ∣ ∣ s [ i − 1 ] = = ′ 2 ′ s[i - 1] == '1' || s[i - 1] == '2' s[i−1]==′1′∣∣s[i−1]==′2′此时既能单独解码又可以和前一个联合解码 因此 d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i−1]+dp[i−2] 如果 s [ i − 1 ] s[i-1] s[i−1]为其他情况则 s [ i ] s[i] s[i]只能单独解码 不能和前一个联合解码 此时 d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i−1]
如果 s [ i ] s[i] s[i]在7~9之间 则如果 s [ i − 1 ] = = ′ 1 ′ s[i-1]=='1' s[i−1]==′1′的情况 既能单独解码又可以和前一个联和解码 因此 d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i−1]+dp[i−2] 此外 d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i−1]
这里的计算解码方法总数 就是计算以s[s.size()-1]结尾的解码方法总数,因此返回
d
p
[
l
e
n
−
1
]
dp[len-1]
dp[len−1]
其实还可以在空间复杂度方面进行优化,像斐波拉契这道题的解法3 这样优化空间复杂度至O(1)
class Solution {
public:
int numDecodings(string s) {
int len = s.size();
if (len == 0 || s[0]=='0')
return 0;
if (len == 1)//处理长度为1的情况
{
if (s[0] == '0')
return 0;
else
return 1;
}
int *dp = new int[len];//根据动态规划要算出 dp[0]和dp[1]才可以继续后面的
dp[0]=s[0]=='0'?0:1;
if (s[1] == '0')
{
if (s[0] == '1' || s[0] == '2')
dp[1] = 1;
else
return 0;
}
else if ('0' < s[1] && s[1] < '7')
{
if (s[0] == '1' || s[0] == '2')
dp[1] = 2;
else
dp[1] = 1;
}
else
{
if (s[0] == '1')
dp[1] = 2;
else
dp[1] = 1;
}
for (int i = 2; i < len; i++)//数组长度大于等于3的情况 运用动态规划
{
if (s[i] =='0')
{
if (s[i - 1] == '1' || s[i - 1] == '2')
{
dp[i] = dp[i - 2];
}
else
return 0;
}
else if ('0' < s[i] && s[i] < '7')
{
if (s[i - 1] == '1' || s[i - 1] == '2')
dp[i] = dp[i - 1] + dp[i - 2];
else
dp[i] = dp[i - 1];
}
else
{
if (s[i-1] == '1')
dp[i] = dp[i-1]+dp[i-2];
else
dp[i] = dp[i-1];
}
}
return dp[len - 1];
}
};
注意
PS:在这个子函数中用到了new 申请了一段堆里面的内存,不管是在子函数中,或是在主函数中,都必须有回一次delete来释放这个空间,如果没有做delete,即使退出程序答,也无法回收这段内存了,内存就被泄露了。