问题描述
小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
问题理解
题目要求我们将一个数字翻译成字符串,并且计算有多少种不同的翻译方法。翻译规则是:0对应"a",1对应"b",依此类推直到25对应"z"。一个数字可能有多种翻译方法。
数据结构与算法选择
-
动态规划:我们可以使用动态规划来解决这个问题。动态规划的核心思想是将问题分解为子问题,并且利用子问题的解来构建原问题的解。
-
状态定义:
dp[i]表示前i个数字可以翻译成字符串的方法数。
-
状态转移方程:
- 如果当前数字可以单独翻译成一个字符(即
s[i-1]在0到9之间),那么dp[i]可以由dp[i-1]转移而来。 - 如果当前数字和前一个数字可以组合成一个有效的字符(即
s[i-2]s[i-1]在10到25之间),那么dp[i]还可以由dp[i-2]转移而来。
- 如果当前数字可以单独翻译成一个字符(即
算法步骤
- 初始化一个长度为
n+1的数组dp,其中n是数字的长度。 dp[0]初始化为1,表示空字符串有一种翻译方法。dp[1]初始化为1,表示单个数字有一种翻译方法。- 从
i=2到n遍历,根据上述状态转移方程更新dp[i]。 - 最终返回
dp[n],即前n个数字可以翻译成字符串的方法数。
public class Main {
public static int solution(int num) {
String s = String.valueOf(num);
int n = s.length();
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
String two = s.substring(i - 2, i);
int p = Integer.parseInt(two);
if (p >= 10 && p <= 25) {
dp[i] = dp[i - 1] + dp[i - 2];
} else {
dp[i] = dp[i - 1];
}
}
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);
}
}
知识点总结
1. 动态规划(Dynamic Programming)
动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。它通常用于解决具有重叠子问题和最优子结构性质的问题。
关键点:
- 状态定义:定义一个状态数组
dp,其中dp[i]表示前i个数字可以翻译成字符串的方法数。 - 状态转移方程:根据当前数字和前一个数字的组合情况,决定如何更新
dp[i]。 - 初始化:
dp[0]和dp[1]的初始化是关键,因为它们是后续状态转移的基础。
2. 字符串操作
- 字符串转换:将数字转换为字符串,以便逐个处理数字。
- 子字符串操作:使用
substring方法获取子字符串,并将其转换为整数进行判断。
3. 边界条件处理
- 空字符串:
dp[0]表示空字符串,初始化为1。 - 单个数字:
dp[1]表示单个数字,初始化为1。
4. 条件判断
在状态转移过程中,需要根据当前数字和前一个数字的组合情况进行条件判断。
关键点:
- 单独翻译:如果当前数字可以单独翻译成一个字符(即
s[i-1]在0到9之间),则dp[i]可以由dp[i-1]转移而来。 - 组合翻译:如果当前数字和前一个数字可以组合成一个有效的字符(即
s[i-2]s[i-1]在10到25之间),则dp[i]还可以由dp[i-2]转移而来。
通过动态规划的思想,我们可以有效地解决数字翻译成字符串的问题。关键在于合理定义状态、设计状态转移方程、处理边界条件,并进行适当的字符串操作和条件判断。