方法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]; }