原题链接Decode Ways
每一个数字和一个字母对应,总共有26个字母,对于每一个或每两个数字,都有可能将其转化成字母,计算有多少中转换形式
以1221为例,所有的转换形式为1->’A’,2->’B’,12->’L’,21->’U’,22->’V’,所有可能的转换结果是
假设给出的数字序列是s[0, 1, …, n],令dp[i - 1]表示s[0, 1, …, i-1]这个数字序列能够表示的所有转化结果个数,那么如何计算dp[i]呢
对于s[0, 1, …, i]这个数字序列的转化结果,可以分成两部分计算
所以直接动态规划计算即可,dp[i]与dp[i - 1]和dp[i - 2]有关,不过有几个边界条件,尤其注意’0’无法转换成对应字母的情况
代码如下
class Solution {
public:
int numDecodings(string s) {
if(s.empty()) return 0;
vector<int> dp(s.size(), 0);
for(int i = 0; i < s.size(); ++i)
{
/* 由s[0,1,...,i-1]+s[i]组成 */
if(s[i] != '0')
dp[i] += (i == 0) ? 1 : dp[i - 1];
/* 由s[0,1,...,i-2]+s[i-1,i]组成 */
if(i > 0 && s[i - 1] != '0' && ((s[i - 1] - '0') * 10 + (s[i] - '0') <= 26))
dp[i] += (i == 1) ? 1 : dp[i - 2];
}
return dp[s.size() - 1];
}
};
代码中处理了i == 0和i == 1的情况,因为i == 0时dp[i - 1]无意义,i == 1时dp[i - 2]无意义
为什么程序中是dp[i] += dp[i - 1]而不是dp[i] += 1 + dp[i - 1]
因为dp[i - 1]表示由s[0, 1, …, i-1]表示的字母集,后面追加一个字母后个数没有改变
以1221为例,假设i == 3,则s[0, 1, …, i - 1]表示的字母集是[ABB, AV, LB],个数dp[i - 1]是3
当后面追加s[i]表示的字母A时,字母集变为[ABBA, AVA, LBA],个数没变,所有dp[i] = dp[i - 1]
当然,dp[i]在初始化时都至为0,所以只需要+=操作即可
原题链接Decode Ways II
要求和上面一样,不同的只是数字集s中可能包含’*’,这个符号可以表示1到9任意一个数字
思想还是动态规划,但是要处理的情况变多了,比如
对于s[0, 1, …, i]由s[0, 1, …, i-1]+s[i]组成的情况,只是简单的多出s[i] == ‘*’的情况而已
而对于s[0, 1, …, j]由s[0, 1, …, i-2]+s[i-1, i]组成的情况,s[i-1, i]需要考虑多种情况,包括
当然,无论多出多少种情况也都不能忽略i == 0和i == 1的情况
首先考虑s[0, 1, …, i]由s[0, 1, …, i-1]+s[i]组成的情况
再考虑s[0, 1, …, i]由s[0, 1, …, i-2]+s[i-1, i]组成的情况
代码如下
class Solution {
public:
int numDecodings(string s) {
if(s.empty()) return 0;
long long int base = 1;
for(int i = 0; i < 9; ++i)
base *= 10;
base += 7;
vector<long long int> dp(s.size(), 0);
for(int i = 0; i < s.size(); ++i)
{
if(s[i] != '0')
{
dp[i] += (s[i] == '*') ? ((i == 0) ? 2 : dp[i - 1] * 2) : ((i == 0) ? 1 : dp[i - 1]);
}
if(i > 0 && s[i - 1] != '0' && (s[i - 1] == '*' || s[i] == '*' || ((s[i - 1] - '0') * 10 + (s[i] - '0') <= 26)))
{
if(s[i - 1] == '*' && s[i] != '*')
dp[i] += (s[i] <= '6') ? ((i == 1) ? 9 : dp[i - 2] * 9) : ((i == 1) ? 1 : dp[i - 2] * 1);
else if(s[i - 1] != '*' && s[i] == '*' && s[i - 1] <= '2')
dp[i] += (s[i - 1] == '1') ? ((i == 1) ? 9 : dp[i - 2] * 9) : ((i == 1) ? 6 : dp[i - 2] * 6);
else if(s[i - 1] == '*' && s[i] == '*')
dp[i] += (i == 1) ? 15 : dp[i - 2] * 15;
else if(s[i - 1] != '*' && s[i] != '*')
dp[i] += (i == 1) ? 1 : dp[i - 2] * 1;
}
dp[i] %= base;
}
return dp[s.size() - 1];
}
};
好多都是用了嵌套()?:表达式,如果不容易理解可以拆开
感觉这两道题不是在考动态规划而是在考脑筋急转弯啊,各种情况想的脑袋疼