问题描述
小M获得了一个任务,需要将数字翻译成字符串。翻译规则是:0对应"a",1对应"b",依此类推直到25对应"z"。一个数字可能有多种翻译方法。小M需要一个程序来计算一个数字有多少种不同的翻译方法。
例如:数字12258可以翻译成 "bccfi", "bwfi", "bczi", "mcfi" 和 "mzi",共5种方式。
测试样例
样例1:
输入:
num = 12258输出:5
样例2:
输入:
num = 1400112输出:6
样例3:
输入:
num = 2110101输出:10
样例4:
输入:
num = 25输出:2
样例5:
输入:
num = 1023输出:4
Solution
这里的难点就是如何进行数字的分配,比如 122 可以分成 abb , mc , bw ,如果单纯的来考虑怎么划分数字的话显然是行不通的。
仔细思考,注意到对于一个长度为 n 的字符串,假设有 f(n) 种方案,如果增加一个数字,那么我们其实只需要关注第 n 位的数字是什么,如果跟第 n+1 位能组成二位数的字母,那么就会有 f(n)+f(n-1) 种方案,否则的话,只会有 f(n) 种方案,别的地方是对最终方案没有影响的.
那么就能够转化到动态规划上了,可以从第 n 位逐渐向前转换成子问题,并且状态转移方程在上面已经给出了.
初始状态:没有字母跟有一个字母都是一种方案 dp[0]=dp[1]=1
Java代码实现
import java.util.Arrays;
public class Main {
public static int solution(int num) {
// Please write your code here
String s = String.valueOf(num);
int n = s.length();
int[] dp = new int[n+1];
Arrays.fill(dp, 0);
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++){
int tmp = (s.charAt(i-2) - '0') * 10 + (s.charAt(i-1) - '0');
dp[i] = dp[i-1];
if(tmp >= 10 && tmp <= 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);
}
}
时空复杂度
时间复杂度: O(n)
空间复杂度: O(n)
总结与思考
这个问题是一个典型的动态规划问题,通过定义状态和状态转移方程,可以有效地计算出数字的不同翻译方法。在实现过程中,还需要注意一下边界条件的处理,例如当数字的某一位是 0 时,不能单独翻译这一位,因为 0 没有对应的字母。此外,还需要注意一下数组的初始化。