题目指路-->数字翻译成字符串的可能性 - MarsCode
问题描述
小M获得了一个任务,需要将数字翻译成字符串。翻译规则是:0对应"a",1对应"b",依此类推直到25对应"z"。一个数字可能有多种翻译方法。小M需要一个程序来计算一个数字有多少种不同的翻译方法。
例如:数字12258可以翻译成 "bccfi", "bwfi", "bczi", "mcfi" 和 "mzi",共5种方式。
测试样例
样例1:
输入:
num = 12258
输出:5
翻译结果可以取[1,2,3,5,8]、[1,22,5,8]、[1,2,25,8]、[12,2,5,8]、[12,25,8]共五种情况。
样例2:
输入:
num = 1400112
输出:6
样例3:
输入:
num = 2110101
输出:10
解题思路:
通过阅读题目可以发现,翻译数字的位数不是一位就是两位,而到第i个数字为止可以翻译的方法数,是基于前面数字的翻译状态所决定的。所以,这个问题的本质就是通过动态规划,计算一个数字可以被翻译成多少种不同的字符串。
动态规划的核心思想
-
状态定义: 定义
dp[i]表示从数字的第i位开始到最后一位可以有多少种翻译方法。 -
递推公式:
- 默认情况下,最后一位数字单独翻译成一个字母,对应的翻译方法和
dp[i-1]相同。 - 如果第
i-1和第i位的数字可以组成有效的字母(即在 10 到 25 之间),则需要额外加上dp[i-2]对应的翻译方法数:
dp[i]=dp[i−1]+dp[i−2]
- 如果不满足两位数字的条件(如大于 25 或小于 10),则
dp[i] = dp[i-1]。
- 初始化:
dp[0] = 1:空串只有一种翻译方法。dp[1] = 1:只有一位数时的翻译方法只有 1 种。
-
边界条件:
- 如果输入的数字是 0 开头的,需要特殊处理,因为数字不能从 0 开头。
完整代码:
//动态规划
public class Main {
public static int solution(int num) {
// Please write your code here
// n个数字共有dp[n]种翻译方法
String str = Integer.toString(num);
int n = str.length();
if (n == 1) return 1;// 只有一位数
int[] dp = new int[n + 1];
dp[0] = 1;//空串的翻译方法有1种
dp[1] = 1;//一位数的翻译方法有1种
for (int i = 2; i <= n; i++) {
//当前遍历到第i个数字
//先默认最后两位无法组成字母,最后一位单独组成字母时
//当前翻译方法=前一位翻译方法
dp[i] = dp[i - 1];
// 截取第i-1和第i个数字组成的字符串A
//str下标是从0开始的
String A = str.substring(i - 2, i);
// 将字符串A转换成数字
int B = Integer.valueOf(A);
//如果当前数字可以和前一个数字组成字母
//则需要加上第i-2位的翻译方法
if (B >= 10 && B <= 25) {
dp[i] += dp[i - 2];
}
}
return dp[n];
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution(12258) == 5);
System.out.println(solution(1400112) == 6);
System.out.println(solution(2110101) == 10);
}
}