leetcode 639. Decode Ways II (动态规划)
639. Decode Ways II
题目链接
题意:
A到Z匹配1到26整数,*匹配1到9的任何数字。给定一个字符串,输出可能有的所有匹配情况。
思路
这题是91. Decode Ways的加强版,我们不妨先考虑简单的情况,比如输入为"112",那么可能有点转化方式为:1 1 2;11 2; 1 12。对于第三个字符2,仅考虑他本身时,可以由1 1, 11 转化而来;当考虑两个字符时(即12时),只能由第一个字符转化而来, 也就是1 12。所以我们不妨记dp[i]表示转化到第i个字符可能有的方法总数,那么有:
- 当仅考虑一个字符组合时,若s[i]!='0’时,有dp[i]=dp[i]+dp[i-1] ,即 1 1 0, 11 0是不符合规范的
- 当考虑连续两个字符组合时,若s[i-1…i]在10到26之间,那么有dp[i]=dp[i]+dp[i-2]成立
现在我们在考虑有"*"的情况,即s[i]==’*’,
- 若只考虑一个字符组合,那么有dp[i]=dp[i]+dp[i-1]*9
- 若考虑两个字符组合,可以分成四类情况:这里统一用d表示出现的地方为数字
4.1 组合为dd,那么只要当dd在10到26之间可以直接转化,dp[i]=dp[i]+dp[i-2]
4.2 组合为**,那么可能的结果为11,12,…,19,21,…,26,即dp[i]=dp[i]+dp[i-2]*15
4.3 组合为d*,那么可能出现的情况为:如果d==1,dp[i]=dp[i]+dp[i-2]*9;如果d==2,那么dp[i]=dp[i]+dp[i-2]*6
4.4 组合为*d,那么可能出现的情况为:如果d在1~6之间,dp[i]=dp[i]+dp[i-2]*2;如果d在7~9之间,dp[i]=dp[i]+dp[i-2]
最后注意开long long,不然乘法爆int
class Solution {
public:
const int Mod=1e9+7;
int numDecodings(string s) {
if(!s.size()) return 1;
int n=s.size();
vector<long> dp(n+1,0);//注意这里直接取 long 类型,不然后面乘法爆int
dp[0]=1;
if(s[0]>='1' && s[0]<='9' ) dp[1]=1;
else if(s[0]=='*') dp[1]=9;
for(int i=1;i<n;i++){
string tmp1=s.substr(i,1);
string tmp2=s.substr(i-1,2);
if(tmp1!="0") {
if(tmp1!="*") dp[i+1]=(dp[i+1]+dp[i])%Mod;
else{
dp[i+1]=(dp[i+1]+dp[i]*9)%Mod;
}
}
//分四种情况讨论
char t1=tmp2[0];
char t2=tmp2[1];
if(isdigit(t1) && isdigit(t2)){//dd
int num2=stoi(tmp2);
if(num2>=10 && num2<=26) dp[i+1]=(dp[i+1]+dp[i-1])%Mod;
}
else if(!isdigit(t1) && !isdigit(t2)){ //** 9+6=15
dp[i+1]=(dp[i+1]+dp[i-1]*15%Mod)%Mod;
}
else if(isdigit(t1) && !isdigit(t2)){ //d*
if(t1=='1') dp[i+1]=(dp[i+1]+dp[i-1]*9%Mod)%Mod;
if(t1=='2') dp[i+1]=(dp[i+1]+dp[i-1]*6%Mod)%Mod;
}
else{//*d
if(t2>='0' && t2<='6') dp[i+1]=(dp[i+1]+dp[i-1]*2%Mod)%Mod;
else dp[i+1]=(dp[i+1]+dp[i-1])%Mod;
}
}
return dp[n];
}
};