法一:递归
思路:很容易想到递归去解决,将大问题化作小问题。
比如 232232323232。
对于第一个字母我们有两种划分方式。
2|32232323232 和 23|2232323232
所以,如果我们分别知道了上边划分的右半部分 32232323232 的解码方式是 ans1 种,2232323232 的解码方式是 ans2 种,那么整体 232232323232 的解码方式就是 ans1 + ans2 种。可能一下子,有些反应不过来,可以看一下下边的类比。
假如从深圳到北京可以经过武汉和上海两条路,而从武汉到北京有 8 条路,从上海到北京有 6 条路。那么从深圳到北京就有 8 + 6 = 14 条路。
public int numDecodings(String s) {
return dfs(s,0);
}
private int dfs(String s, int start) {
if(start==s.length())
return 1;
if(s.charAt(start)=='0') //如果开头是0则不对应任何字母
return 0;
int ans1 = dfs(s,start+1);
int ans2 = 0;
if (start < s.length() - 1) {
int ten = (s.charAt(start) - '0') * 10;
int one = s.charAt(start + 1) - '0';
if (ten + one <= 26) {
ans2 = dfs(s, start + 2);
}
}
return ans1+ans2;
}
法二:记忆化(递归优化)
解法一的递归中,走完左子树,再走右子树会把一些已经算过的结果重新算,所以我们可以用 memoization 技术,就是算出一个结果很就保存,第二次算这个的时候直接拿出来就可以了。
public int numDecodings(String s) {
Map<Integer,Integer> map = new HashMap<>();
return dfs(s,0,map);
}
private int dfs(String s, int start, Map<Integer, Integer> map) {
if(start==s.length())
return 1;
if(s.charAt(start)=='0') //如果开头是0则不对应任何字母
return 0;
int mem = map.getOrDefault(start,-1);
if(mem!=-1)
return mem;
int ans1 = dfs(s,start+1, map);
int ans2 = 0;
if (start < s.length() - 1) {
int ten = (s.charAt(start) - '0') * 10;
int one = s.charAt(start + 1) - '0';
if (ten + one <= 26) {
ans2 = dfs(s, start + 2, map);
}
}
map.put(start,ans1+ans2);
return ans1+ans2;
}
法三:动态规划
同样的,递归就是压栈压栈压栈,出栈出栈出栈的过程,我们可以利用动态规划的思想,省略压栈的过程,直接从 bottom 到 top。
用一个 dp 数组, dp [ i ] 代表字符串 s [ i, s.len-1 ],也就是 s 从 i 开始到结尾的字符串的解码方式。
这样和递归完全一样的递推式。
如果 s [ i ] 和 s [ i + 1 ] 组成的数字小于等于 26,那么
dp [ i ] = dp[ i + 1 ] + dp [ i + 2 ]
public int numDecodings(String s) {
int len = s.length();
int[] dp = new int[len + 1];
dp[len] = 1; //将递归法的结束条件初始化为 1
//最后一个数字不等于 0 就初始化为 1
if (s.charAt(len - 1) != '0') {
dp[len - 1] = 1;
}
for (int i = len - 2; i >= 0; i--) {
//当前数字时 0 ,直接跳过,0 不代表任何字母
if (s.charAt(i) == '0') {
continue;
}
int ans1 = dp[i + 1];
//判断两个字母组成的数字是否小于等于 26
int ans2 = 0;
int ten = (s.charAt(i) - '0') * 10;
int one = s.charAt(i + 1) - '0';
if (ten + one <= 26) {
ans2 = dp[i + 2];
}
dp[i] = ans1 + ans2;
}
return dp[0];
}
来源:CSDN
作者:花粥没有花
链接:https://blog.csdn.net/weixin_44718349/article/details/103876175