leetcode-剑指 Offer 46. 把数字翻译成字符串
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
提示:
0 <= num < 231
解题方法:
法一:动态规划
dp[i]代表到当前第i位为止,有多少种翻译方式。翻译方式分为两类:
a.只翻译当前的一位
b.将当前的第i位字符与第I-1位组合起来翻译
比如:316
a. 6可以单独翻译,那么dp[i]=dp[i-1]+1 ,这里不是+1,因为是在31的方法上里的同一种方法,它们是一种翻译方法。
b. 6可以单独翻译,也可以和他的前一位1一起翻译,也就是组成16,
即dp[i]=dp[i-1]+dp[i-2](注意:这里需要判定数字的范围 若数字为356 那么56是不满足一起组合翻译的条件的,所以组合的数字要求是在10-25之间的)
class Solution {
public:
int translateNum(int num) {
string s=to_string(num);
int n=s.size();
vector<int> dp(n+1,0);
dp[0]=1,dp[1]=1;
for(int i=2;i<n+1;i++)
{
if(s[i-2]=='1'||(s[i-2]=='2'&&s[i-1]<'6'))
dp[i]=dp[i-1]+dp[i-2];
else
dp[i]=dp[i-1];
}
return dp[n]];
}
};
法二:迭代
若数字在0-9之间,那么只有一种方法,所以这是递归的出口。
if(num<10) return1;
由于需要特殊判定的10-25可以组成两种方式的翻译方法,要么单一翻译,要么组合在一起翻译:
a. num%100如果在10-25之间,那么就是两种递归情况叠加(num/10)是单独翻译,(num/100)是两位一起翻译。
b. num%100<10或者num%100>25 当前这一位只能自己独自翻译,所以继续迭代前面其余的数字(Num/10)
class Solution {
public:
int translateNum(int num) {
if(num<10) return 1;
if(num%100<10||num%100>25) return translateNum(num/10);
else return translateNum(num/100)+translateNum(num/10);
}
};
法三:回溯
class Solution {
int res=0;
void dfs(string &s,int start)
{
int len=s.size();
if(start>=len) //终止条件
{
res++;
return ;
}
dfs(s,start+1); //a情况:独自翻译
if(start<len-1&&s[start]>='1'&&s[start]<='2') //b情况
{
if(s[start] =='1' || s[start] == '2' &&s[start+1]<'6')
dfs(s,start+2);
}
}
public:
int translateNum(int num) {
string s=to_string(num);
dfs(s,0);
return res;
}
};