剑指 Offer 46. 把数字翻译成字符串

题目描述:

给定一个数字,我们按照如下规则把它翻译为字符串: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

链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/solution/mian-shi-ti-46-ba-shu-zi-fan-yi-cheng-zi-fu-chua-6/

 

代码如下:

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];
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值