很坑,亲测输入会出现0,而且从前往后条件真的多到哭,面向if-else
编程,我真的想死:
class Solution {
public:
int dp(string& s, int i, int j){
int n = j - i + 1;
if(n == 0) return 0;
if(n == 1) return s[i] == '0' ? 0 : 1;
if(n == 2){
if(s[i] == '0') return 0;
if(s[i] > '2') return s[j] == '0' ? 0 : 1;
if(s[i] == '2' && s[j] > '6') return 1;
if(s[j] == '0') return 1;
return 2;
}
if(s[i] > '2') return dp(s, i+1, j);
if(s[i] == '2'){
if(s[i+1] == '0') return dp(s, i+2, j);//"20"开头
else if(s[i+1] < '7') return dp(s, i+1, j) + dp(s, i+2, j);// > "26"
else return dp(s, i+1, j);
}
if(s[i] == '0') return 0;//首元素为0
if(s[i+1] == '0') return dp(s, i+2, j);//首元素为1,次元素为0
return dp(s, i+1, j) + dp(s, i+2, j);
}
int numDecodings(string s) {
return dp(s, 0, s.size()-1);
}
};
上述代码判断条件繁多,递归栈很深,而且效率极低。。。
正确方法肯定不是这样的。
假设我们现在考虑已经解码了字符串的前i-1个字符,现在轮到了第 i 个字符,进行分情况讨论(dp[i]表示前 i 位的解码方法种数):
1、如果s[i] == '0'
,那么s[i]
不能单独解码,必须和它前面的字符s[i-1]
联合:
- 如果
s[i-1]
= 1 or 2,那么s[i-1]s[i]
只能被联合译码,而且只有这一种情况:dp[i] = dp[i-2] - 如果
s[i-1]
是 0 或者3~9,那么就无法译码,直接 return 0。
2、当s[i] != '0'
时:
- 如果
s[i-1] == '1'
,此时,s[i]可以和s[i-1]可以联合译码,也可以单独译码,dp[i] = d[i-1] + dp[i-2] - 如果
s[i-1] == '2'
&&s[i] <= '6'
,此时s[i]可以和s[i-1]可以联合译码,也可以单独译码,dp[i] = d[i-1] + dp[i-2] - 其他的情况,s[i], s[i-1]只能分开单独译码,dp[i] = dp[i-1]
稍许调整翻译成初步代码:
class Solution {
public:
int numDecodings(string s) {
int n = s.size();
if(n == 0 || s[0] == '0') return 0;//首尾为0无法解码
vector<int> dp(s.size() + 1);
dp[0] = 1; dp[1] = 1;
for(int i = 1; i < n; ++i){
if(s[i] == '0') {
if(s[i-1] == '1' || s[i-1] == '2') dp[i+1] = dp[i-1];
else return 0;
}else{
if(s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6')) dp[i+1] = dp[i] + dp[i-1];
else dp[i+1] = dp[i];
}
}
return dp.back();
}
};
最近动态规划题目做了挺多的,但是很多时候拿到新题目还是会没思路,做不到举一反三-_-
如果需要进行优化的话,可以看到状态 i 最多只和前面两个 i-1, i-2有关,所以三个遍变量或者两个变量就能实现状态转移。
class Solution {
public:
int numDecodings(string s) {
int n = s.size();
if(n == 0 || s[0] == '0') return 0;
//vector<int> dp(s.size() + 1);
//dp[0] = 1; dp[1] = 1;
int pre = 1, cur = 1;
int tmp;
for(int i = 1; i < n; ++i){
tmp = cur;
if(s[i] == '0') {
if(s[i-1] == '1' || s[i-1] == '2') cur = pre;
else return 0;
}else{
if(s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6')) cur = cur + pre;
//else cur = cur;//可以省略
}
pre = tmp;
}
return cur;
}
};