题目
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
方法一 递归
这道题我最先想到的方法是递归,从第一个数开始,每次取当前数字或先后取一个组成两位数,如果能够成功取到最后一位数,就将结果数加一,递归的返回条件就是索引到最后一个数组处。
具体分析,首先将数字转换为字符串,以便于截取其中的一位或两位。
**递归初始值:**由数字组成的字符串s,递归开始的索引idx,两个参数组成,idx从0开始递归。
**递归方式:**当索引idx的值小于s的长度时才继续向下递归,递归包含两种情况,一种是当前数字,递归向下,idx+1;另外一种是包含两个数字,且这个两位数在10~25之间,递归向下,idx+2。
递归结束条件: 当idx的值为字符串s的长度时,说明此时正好取到了最后一位数,res的值自增1,返回上一层。0
代码1
class Solution {
int res = 0;
public int translateNum(int num) {
String s = String.valueOf(num);
dfs(s,0);
return res;
}
public void dfs(String s,int idx){
if(idx == s.length()){
res++;
return;
}
//递归1个数字
if(Integer.parseInt(s.substring(idx,idx+1) ) < 26)
dfs(s,idx+1);
//递归2个数字
if(idx < s.length()-1 && Integer.parseInt(s.substring(idx,idx+2)) < 26 && Integer.parseInt(s.substring(idx,idx+2)) >= 10) //当idx小于s的长度减1时才能选取substring,并且数字在10~25之间才递归
dfs(s,idx+2);
}
}
复杂度
时间复杂度:O(N),递归从头到尾一遍遍历。
空间复杂度:O(1),没有额外空间。
注意点
递归特别注意结束条件,以及在进行选择了两个数字的下次递归,防止索引越界。
方法二 动态规划
刚开始我还没想到用动态规划,通过递归解答完毕后看了一下其他人的思路才发现,动态规划解题更好理解,会觉得本题更简单。下面看看动态规划的几个步骤。
状态定义:定义数组dp,dp[i]为前i个位置的数字翻译法数。那么一定存在一定关系,可以通过前面已知值得到当前值;
状态转移方程:有两种情况,当当前数字和前一个数字组成的一个两位数数字的范围在10~25时,dp[i] = dp[i-1] + dp[i-2],其他情况则是dp[i] = dp[i-1];
初始化:首先需要初始dp[0] = dp[1] = 1;
输出值:dp[length]即为要求的结果。
代码2
class Solution {
public int translateNum(int num) {
String s = String.valueOf(num);
int[] dp = new int[s.length()+1];
dp[0] = 1;dp[1] = 1;
for(int i = 1;i<s.length();i++){
String str = s.substring(i-1,i+1);
//if(Integer.parseInt(str) >=10 && Integer.parseInt(str) < 26)
if(str.compareTo("10") >= 0 && str.compareTo("25") <= 0)
dp[i+1] = dp[i-1] +dp[i];
else
dp[i+1] = dp[i];
}
return dp[s.length()];
}
}
复杂度
时间复杂度:O(N),空间复杂度:O(N),引入了数组存放动态值。
由于dp[i]和dp[i-1] 和dp[i-2]有关系,可以通过常数的变量记录dp[i-1]和dp[i-2]的值,每次不断更新。
所以通过cur记录当前位置的翻译方法数,pre记录前一个位置的翻译方法数,prepre记录pre的前一个翻译方法数,每次计算完了当前cur的值,更新prepre为pre的值,而pre的值为cur的值进行下一次循环,直到循环到最后一个数字,返回cur即为最总结果。
代码3
class Solution {
public int translateNum(int num) {
String s = String.valueOf(num);
int prepre = 1,pre = 1,cur = 1;
for(int i = 1;i<s.length();i++){
String str = s.substring(i-1,i+1);
//if(Integer.parseInt(str) >=10 && Integer.parseInt(str) < 26)
if(str.compareTo("10") >= 0 && str.compareTo("25") <= 0){
cur = prepre + pre;
}else{
cur = pre;
}
prepre = pre;
pre = cur;
}
return cur;
}
}
复杂度
时间复杂度:O(N),空间复杂度:O(1).