题目
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
样例
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
思路分析
动态规划:
状态定义:
dp[n] 表示前n位,有多少种不同的翻译方法
分析:
分类:
以最后一位翻译而成的可能性进行分类
第一种:要么单独翻译
第二种:连同前面的一起翻译
前n位总的种类数怎么构成,存在两种可能性
第一种可能:第n位不与前面组合比如 1225 ,为122组合完成的基础上,将5单独翻译,那么该种类数就是122的种类数
第二种可能:第n位与前面组合比如1225,组合为12 和 25 那么种类数为12有多少种,那么12,25就有多少种
所以dp[n] = part1 + part2组合而成
part1 = dp[n-1]
part2 = dp[n-2]但是需要判断后两位是否能组合成11-25之间的数,能那么par2 = dp[n-2] ,不在的话那么说明part2这种可能性不存在,那么part2 = 0
代码
package 剑指offer.动态规划.offer46;
public class Solution {
public static void main(String[] args) {
Solution solution = new Solution();
int test = 12258;
int res = solution.translateNum(test);
System.out.println(res);
}
/**
* 思路分析
* 动态规划:
*
* 状态定义
* dp[n] 表示前n个数字能翻译的种类数
*
* 状态方程:
* n >1 部分组合dp[n]/ part1 = dp[n-1]
* 最后两位当成整体n >2 前提 10<= num[n-1]num[n] <= 25 部分组合dp[n]/part2 = dp[n-2]
* 如果最后两位分散呢? dp[n-1]已经包含了这种可能
*
* dp[n] = 两部分的和即part1 + part2
*
*
*
* 初始值:
* dp[0] = 1
* dp[1] = 需要计算
*
* @param num
* @return
*/
public int translateNum(int num) {
//转化为字符串处理
String numStr = num + "";
StringBuilder numBuilder = new StringBuilder(numStr);
int length = numBuilder.length();
int[] dp = new int[length];
//初始化值
dp[0] = 1;
//这里就针对只输入了一位数
if(length==1){
return 1;
}
//我想要截取0-1包括1但是substring不包括所以要+1
String strOne = numBuilder.substring(0, 1+1);
if(contains(strOne)){
dp[1] = 2;
}else {
dp[1] = 1;
}
if(length > 2) {
for (int i = 2; i < length; i++) {
int part1 = 0;
int part2 = 0;
part1 = dp[i - 1];
//i需要+1,因为我要取(i-1,i)
String part2Str = numBuilder.substring(i - 1, i + 1);
if (contains(part2Str)) {
part2 = dp[i - 2];
}
dp[i] = part1 + part2;
}
}
return dp[length-1];
}
//判断这个字符串是否能组成合法的两位数
Boolean contains(String str){
int num = Integer.parseInt(str);
if(num < 10){
return false;
}
if(num > 25){
return false;
}
return true;
}
}