详情参见leetcode 91.解码方法
我的解法:
dfs深度遍历优先搜索,遇到错误情况返回。
错误情况包含以下三种:
- 单个为0或者两个字符以0为前导;
- 两个字符的值大于26 即不为A~Z;
- 整个字符转含有前导0。
但是因为字符串长度为 1 ≤ length ≤ 1000,采用dfs的开销太大,超出时间限制,故不可取。
代码如下:
class Solution {
public:
int answer=0;//计数
string str;//全局存储
void dfs(int cur) {
if(cur>=str.size()) {
answer++;
return;
}
if(str[cur]=='0') return;
dfs(cur+1);//第一种情况
if(cur<=str.size()-2) {//第二种情况
if( (str[cur]-'0')*10 + (str[cur+1]-'0') <= 26 ) {
dfs(cur+2);
}
}
return;
}
int numDecodings(string s) {
str=s;
if(str[0]=='0') return 0;//当含有前导0时 返回0
if(str.size()==1) return 1;//仅含有一个数据元素时
dfs(1);
if( (str[0]-'0')*10 + (str[1]-'0') <= 26) {//不超过限制时
dfs(2);
}
return answer;
}
};
动态规划解法:
对于一个确定的字符串 s 而言,当在其后添加一个字符后,按照题目要求存在的情况,
其能组成的所有可能为:s 的所有情况 + ( s - s [length-1] )的所有情况 (当然还有排除不存在的情况)
不妨设:s 的长度为n,并且从左至右的字符串分别为 s [1] 、s [2] …s[n];
故我们可以使用动态规划的方法,计算出每一个 s [ i ] 阶段所含有的满足题意的解码方法数。
由最开始的描述,具体地,设 f [ i ] 表示字符串 s 的前 i 个字符 s[1…i] 的解码方法数。
在进行状态转移时,我们可以考虑最后一次解码使用了 s 中的哪些字符,那么会有下面的两种情况:
- 如果 s [ i ] ≠ 0,那么它就可以被单独分解,故 f [ i ] = f [ i - 1 ];
- 对 s [ i - 1] 和 s [ i ]进行组合编码,并且s [ i - 1] ≠ 0 和 二者组成的字符串不能大于26,故f [ i ] = f [ i - 2 ];
动态规划的边界条件设置为 f [ 0 ] = 1,空字符串也是一种可能 (因为 length≥1 )
class Solution {
public int numDecodings(String s) {
int n = s.length();
int[] f = new int[n + 1];
f[0] = 1;//动态规划的边界条件
for (int i = 1; i <= n; ++i) {
if (s.charAt(i - 1) != '0') {
f[i] += f[i - 1];//单个字符情况
}
if (i>1 && s.charAt(i-2) != '0' && ((s.charAt(i-2)-'0') * 10 + (s.charAt(i-1)-'0') <= 26)) {
f[i] += f[i - 2];//双个字符情况
}
}
return f[n];
}
}