思路
这个问题是一个典型的动态规划问题。我们需要找到给定数字的所有可能翻译方式,每个数字(0-9)可以单独翻译,如果它和前一个数字组成的两位数在10到25之间,也可以一起翻译。因此需要一个数组来记录到当前数字为止的所有可能翻译方式的数量。
假设我们有一个数字 12258:
-
初始状态:
dp[0] = 1:空字符串有一种翻译方式(即不进行任何翻译)。dp[1] = 1:第一个数字有一种翻译方式。
-
迭代计算:
- 对于
i = 2,numStr[1:2] = "22"(无效),numStr[1] = "2"(有效),dp[2] = dp[1] = 1。 - 对于
i = 3,numStr[2:3] = "22"(有效),numStr[2] = "2"(有效),dp[3] = dp[2] + dp[1] = 2。 - 对于
i = 4,numStr[3:4] = "25"(有效),numStr[3] = "5"(有效),dp[4] = dp[3] + dp[2] = 3。 - 对于
i = 5,numStr[4:5] = "58"(无效),numStr[4] = "8"(有效),dp[5] = dp[4] = 3。 - 对于
i = 6,numStr[5:6] = "8"(无效),但numStr[4:6] = "258"(这里我们只考虑两位数,所以实际上不会考虑三位数,但为了完整性,理论上如果允许三位数翻译,这里需要判断),numStr[5] = "8"(有效),dp[6] = dp[5] + dp[4]中有效的部分(即考虑"25")= 5。
- 对于
代码详解
public class Main {
public static int solution(int num) {
String numStr = String.valueOf(num);
int n = numStr.length();
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
int singleDigit = Integer.parseInt(numStr.substring(i - 1, i));
int doubleDigit = Integer.parseInt(numStr.substring(i - 2, i));
// 单独一个数字总是有效的
if (singleDigit >= 0 && singleDigit <= 9) {
dp[i] += dp[i - 1];
}
// 两位数字在10到25之间有效
if (doubleDigit >= 10 && doubleDigit <= 25) {
dp[i] += dp[i - 2];
}
}
return dp[n];
}
public static void main(String[] args) {
System.out.println(solution(12258) == 5); // true
System.out.println(solution(1400112) == 6); // true
System.out.println(solution(2110101) == 10); // true
}
}
知识总结
- 动态规划:通过记录子问题的解来避免重复计算,从而优化时间复杂度。
- 字符串操作:通过
substring方法提取字符串的一部分进行数字转换。 - 边界条件处理:在处理字符串和数字时,注意检查边界条件,例如索引不要越界。
理解
动态规划的核心思想是将问题分解为更小的子问题,并记录这些子问题的解,从而避免重复计算。在这个问题中,我们通过 dp 数组记录了到当前位置为止的所有可能翻译方式的数量。
学习建议
- 理解基本概念:确保你对动态规划的基本概念有清晰的理解,如状态转移方程、边界条件等。
- 多做练习:通过大量的练习来熟悉动态规划的应用和技巧。
- 代码实现:不要仅仅停留在理解算法思路上,要亲手实现代码,调试并优化。 。