题目:
给定一个数字,我们按照如下规则把它翻译为字符串:
0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例:
输入:12258
输出:5
12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
思路:
- 我们可以把这道题当成有条件的跳台阶来做,本质还是动态规划
- 我们可以定义一个动态数组
dp[]
,每一个dp[i]
表示前i个数字能翻译出来的所有字母情况,所以遍历一遍之后,最后的dp[len]就是数组中所有数字能组成的所有结果 - 假设每个数字和前一个数字组合起来的数字为
temp
,每一个dp[i]的获取有两种情况:- 当前数字和前一个数字能够组成一个新的字母,也就是
temp>=10&&temp<=25
,即dp[i]=dp[i-1]+dp[i-2]
- 当前数字和前一个数字不能组成一个新的字母,也就是temp大小不在上述范围:即
dp[i]=dp[i-1]
- 当前数字和前一个数字能够组成一个新的字母,也就是
- 注意:由于给的是数字,因此我们需要先将数字先转换成字符串,然后再通过
compareTo
方法进行比较即可 - 是不是和跳台阶的做法很像?只是跳两级的时候多了一个条件限制
- 最后,返回
dp[len]
即可
以下为代码+注释:
public int translateNum(int num) {
// 动态规划dp
String str = String.valueOf(num);
int len = str.length();
int[] dp = new int[len + 1];
// dp[i] 表示前i个字母能够翻译的不同字符串数量
// 由于我们前两个数字比如23是在10-25范围中的的,因此dp[2]=dp[0]+dp[1]=2,所以我们应该把dp[0]直接设置为1
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= len; i++){
String temp = str.substring(i - 2, i);
if(temp.compareTo("10") >= 0 && temp.compareTo("25") <= 0){
dp[i] = dp[i - 1] + dp[i - 2];
}else{
dp[i] = dp[i - 1];
}
}
return dp[len];
}
由于我们每一次遍历只关心上一个和上上一个的数值情况,因此我们可以使用两个变量来代替dp数组,优化后
时间复杂度为O(n):遍历了一次整个字符串,长度为n
空间复杂度为O(n):定义了一个字符串变量
以下为优化过的代码:
public int translateNum(int num) {
// 表示上一个的情况
int preOne = 1;
// 表示上上一个的情况
int preTwo = 1;
String str = String.valueOf(num);
int len = str.length();
for(int i = 2; i <= len; i++){
int cur = 0;
String temp = str.substring(i - 2, i);
if(temp.compareTo("10") >= 0 && temp.compareTo("25") <= 0){
cur = preOne + preTwo;
}else{
cur = preOne;
}
// 每次遍历过当前情况之后都要记得更新两个变量
preTwo = preOne;
preOne = cur;
}
return preOne;
}
笔者也是在不断学习的学生,如有错误,欢迎指正!