问题描述
小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
思路
这个问题可以通过动态规划来解决。我们可以定义一个数组 dp,其中 dp[i] 表示数字字符串的前 i 位有多少种翻译方法。对于每个数字,我们有两种选择:
- 单独翻译当前数字。
- 如果当前数字和前一个数字可以组成一个有效的两位数(即在 10 到 25 之间),则将前两个数字一起翻译。
我们创建一个动态规划数组,并对其进行分解:
dp[1] = 1 ('1' -> 'b')
dp[2] = dp[1] + (如果 '12' 可以组合翻译) dp[0] = 1 + 1 = 2
dp[3] = dp[2] + (如果 '22' 可以组合翻译) dp[1] = 2 + 1 = 3
dp[4] = dp[3] + (如果 '25' 可以组合翻译) dp[2] = 3 + 2 = 5
dp[5] = dp[4] + (如果 '58' 可以组合翻译) dp[3] = 5 + 0 = 5
下面是ac代码:
public static int solution(int num) {
String str = String.valueOf(num);
int n = str.length();
if (n == 0) return 0;
if (n == 1) return 1;
// 动态规划数组
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1];
int twoDigit = Integer.parseInt(str.substring(i - 2, i)); // 当前字符及前一个字符形成的数
if (twoDigit >= 10 && twoDigit <= 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);
}
}
知识点总结:
通过解决数字翻译成字符串的问题,我们学习了以下几个关键知识点:
- 动态规划(DP):它的核心在于两个主要概念:最优子结构和重叠子问题。最优子结构意味着一个问题的最优解可以通过其子问题的最优解来构建。而重叠子问题则是指在解决问题的过程中,相同的子问题会被重复计算多次。
- 状态转移方程:在本题中,状态转移方程是这样的:
dp[i] = dp[i-1] + (if applicable) dp[i-2]。这表示第i位的翻译方法数量等于第i-1位的翻译方法数量,再加上如果第i-2位和第i-1位可以组合翻译的话,第i-2位的翻译方法数量。
青训营学习计划
- 每日刷题:每天至少解决一道算法题,保持思维的活跃性。
- 专题学习:每周或每月选择一个算法专题进行深入学习,如排序算法、图算法等。
- 错题回顾:定期回顾错题,分析错误原因,避免重复犯错。
工具运用
- 在线学习平台:利用豆包MarsCode AI 刷题平台进行练习,同时结合其他在线课程和教程。
- 算法书籍:阅读经典算法书籍,如《算法导论》、《算法设计手册》等,作为理论学习的补充。
- 编程环境:使用IDE(如IntelliJ IDEA、Visual Studio Code)进行代码编写和调试。