方法1: 递归:将大问题化解为小问题
public class Solution {
public int solve (String nums) {
return back(nums.toCharArray(), 0);
}
// 递归函数
public int back(char[] nums, int start){
//当start走到终点时,证明已经解码完毕,直接返回1
if(start == nums.length){
return 1;
}
//当字符为0的时候,0没对应的解码,所以直接返回0 (此路解码废掉)
if(nums[start] == '0')
return 0;
//每次解码一个字符
int res1 = back(nums,start+1);
int res2 = 0;
//如果当前字符等于1 或者 当前字符加上下一个字符合起来小于等于26 则可以一次解码两个字符
if((start < nums.length-1) && (nums[start] == '1' || (nums[start] == '2' &&nums[start+1] <= '6'))){
res2 = back(nums,start+2);
}
//返回结果
return res1 + res2;
}
}
方法二: 动态规划代码分析:
dp[i] 表示字符串nums中以i个位置结尾的前缀字符串的解码种数
例如 nums = "123", 此时dp[0]=1,dp[1]=2,dp[2]=3
分类讨论:
- 当前字符不等于0的时候,dp[i] = dp[i-1],此时将当前位置的一个字符译码
- 当前字符+前一个字符,记为num, 如果
10<=num<=26此时符合两个合并一起译码的条件;
- 若此时i等于1,直接dp[i]++;
- 大于1, 则dp[i] += dp[i-2];
- 举个例子: nums = "324"
- 此时dp[0] = 1, dp[1]呢? dp[2]呢?
- 很明显nums[1] != '0',所以dp[1] = dp[0],num = 32,此时不满足两个一起译码的条件则循环往下执行,此时 nums[2] != '0',则 dp[2] = dp[1] = 1, num = 24,此时满足两个一起译码的条件,因为i==2大于1,所以dp[2] += dp[2-2] ,dp[2] = 1+1 = 2。
总的来说,其实这道题目很像爬楼梯,一次能爬一层和爬两层,只是爬的过程中增加了一些限定条件,只要将这些限定条件屡清楚则可以完全搞懂这类题目~
public int solve (String nums) {
if(nums.length() == 0 || nums.charAt(0) == '0')
return 0;
int[] dp = new int[nums.length()];
dp[0] = 1;
for(int i = 1; i < dp.length; i++){
if(nums.charAt(i) != '0'){
dp[i] = dp[i-1];
}
// 3 2 4
int num = (nums.charAt(i-1)-'0')*10 + (nums.charAt(i)-'0');
if(num >= 10 && num <= 26){
if(i == 1){
dp[i] += 1;
}else{
dp[i] += dp[i-2];
}
}
}
return dp[nums.length()-1];
}

京公网安备 11010502036488号