题目描述:
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
0 <= num < 2^31
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
这道题没看题解自己写出来了,思路也算比较简单,递归+回溯。很容易发现的一个规律,对于1开头或者2开头的数字,如果和后面的数字组成的数组<=25,那么就有两种拼法。举个例子,23这个数字,如果每一位单独看,可以翻译成cd,如果连在一起看,就可以翻译成x。但对于36就不可以,因为整数36没有对应的字母,只能翻译成dg。
故此,如果在遇到一个数字时,如果他只能翻译成一个字母,那么就把这个字母加入到str中,继续进行下一次递归,递归返回后删除该字母。如果它还可以带着后面的数字一起翻译成一个字母,那就把组合而成的这个字母加入到str中,继续进行下一次递归,递归返回后删除该字母。
代码如下:
class Solution {
public:
// res用来存放每个翻译结果
vector<string> res;
// 栈s用来存放数字的每一位
stack<int> s;
int translateNum(int num) {
// 数字的每一位依次入栈
while(num)
{
int temp=num%10;
s.push(temp);
num=num/10;
}
// 进行递归
string str="";
dfs(str);
// 返回结果
return res.size();
}
void dfs(string str)
{
// 如果栈为空,说明所有数字已经都翻译完了,本次翻译结果存入res
if(s.empty())
{
res.push_back(str);
return;
}
// 如果栈不空,那么获取栈顶元素
int first=s.top();
s.pop();
// 翻译栈顶元素并加入str
char c='a'+first;
str=str+c;
// 进行下一次递归
dfs(str);
// 递归完成后删除刚才加入的字母
str.erase(str.end()-1);
// 如果栈不空
if(!s.empty())
{
// 获取下一位数字和本数字组成一个新的数字temp,例如1和5组成15
int second=s.top();
s.pop();
int temp=first*10+second;
// 如果这个数字<=25,并且第一位为1或者2
if(temp<=25&&(first==1||first==2))
{
// 就把这个组成的新数字翻译
c='a'+temp;
str=str+c;
// 进行下一次递归
dfs(str);
// 递归完成后删除刚才加入的字母
str.erase(str.end()-1);
}
// 把刚才弹出的第二个元素重新入栈
s.push(second);
}
// 把刚才弹出的第一个元素重新入栈
s.push(first);
return;
}
};
看了看题解,有另一种思路,是关于动态规划的,思路如下:
来源:leetcode用户 Krahets
代码如下:
class Solution {
public:
int translateNum(int num) {
// nums用来存储num的每一位
vector<int> nums;
// 如果num刚开始就为0,那么就把0假如nums
if(num==0) nums.push_back(0);
// 依次把num的每一位反向添加到nums中
while(num)
{
int temp=num%10;
nums.push_back(temp);
num=num/10;
}
// 反转nums
reverse(nums.begin(),nums.end());
// 申请一个数组dp,长度为nums的长度,dp[i]代表以i结尾的数字串可以翻译的种数
int dp[nums.size()];
// 第一个数字只有一种翻译方式
dp[0]=1;
// 如果num只有1位数字,那么直接返回一种翻译方式即可
if(nums.size()==1)
return 1;
int temp=nums[0]*10+nums[1];
// 来判断第二位数字有几种翻译方式,其实也是递推方程
// 1.如果上一位数字无法与本位数字合并组成一种新的翻译方式,那么以本位数字结尾的数字串,翻译种数就是以上一位数字结尾的数字串的翻译种数
// 即dp[i]=dp[i-1];
// 2.如果上一位数字无可以与本位数字合并组成一种新的翻译方式,那么以本位数字结尾的数字串,翻译种数就是以上一位数字结尾的数字串的翻译种数+以上上一位数字结尾的数字串的翻译种数
// 即dp[i]=dp[i-1]+dp[i-2];
if((nums[0]==1||nums[0]==2)&&temp<=25)
dp[1]=2;
else
dp[1]=1;
// 从第三位数字开始,应用递推方程
for(int i=2;i<nums.size();i++)
{
int temp=nums[i-1]*10+nums[i];
if((nums[i-1]==1||nums[i-1]==2)&&temp<=25)
dp[i]=dp[i-1]+dp[i-2];
else
dp[i]=dp[i-1];
}
// 返回最后的总数
return dp[nums.size()-1];
}
};