【LeetCode 把数字翻译成字符串】

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

题目描述

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

示例 1:

输入: 12258 输出: 5 解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

提示:

  • 0 <= num < 231

作者:Krahets 链接:力扣 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路

根据题意,可按照下图的思路,总结出 “递推公式” (即转移方程)。

因此,此题可用动态规划解决,以下按照流程解题。

动态规划解析:

  • 记数字 num 第 i 位数字为 x[i] ,数字 num 的位数为 n ;

  • 例如:num=12258 的 n=5 , x [1]=1 。

|状态定义: 设动态规划列表 dp[i] 代表以 x[i]为结尾的数字的翻译方案数量。

|转移方程: 若 x[i]和 x[i-1] 组成的两位数字可被整体翻译,则dp[i]=dp[i−1]+dp[i−2] ,否则 dp[i]=dp[i−1] 。

 

可被整体翻译的两位数区间分析: 当 x[i−1]=0 时,组成的两位数无法被整体翻译(例如 00,01,02,⋯ ),大于 25 的两位数也无法被整体翻译(例如 26,27,⋯ ),因此区间为 [10,25] 。

  • 初始状态: dp[0]=dp[1]=1 ,即 “无数字” 和 “第 1 位数字” 的翻译方法数量均为 1;

  • 返回值: dp[n] ,即此数字的翻译方案数量;

|Q: 无数字情况 dp[0]=1 从何而来?

|A: 当 num 第 1,2 位的组成的数字 ∈[10,25] 时,显然应有 =2 种翻译方法,即 dp[2]=dp[1]+dp[0]=2 ,而显然 dp[1]=1 ,因此推出 |dp[0]=1 。

字符串遍历

这里采用了动态规划的思想,通过状态转移方程来求解最终答案。

具体来说,我们使用两个指针 a 和 b 来记录当前位置之前的数字可以被翻译成多少个字符。一开始,a 和 b 的值均为1,表示第一个数字只能翻译成一个字符;然后从第二个数字开始遍历整个数字串。对于当前数字,我们取其当前数字和前一个数字组成的两位数,如果这个数在10-25的范围内,则当前位置可以翻译成 a+b 种不同的字符,否则只能翻译成 a 种字符。接着更新 a 和 b 的值,将 b 更新为 a,将 a 更新为当前位置可以翻译成的字符数量。最终返回 a 即可。

这道题目和斐波那契数列问题类似,都是使用动态规划的思想。

虽然此题和斐波那契数列都可以使用动态规划的思想来解决,但是它们两者在具体的实现细节上还是有些不同的。

  • 首先,在斐波那契数列中,每个数字的值只与前面的两个数字有关。而在这道题中,每个数字的值不仅与前面一个数字有关,还与前面两个数字组成的两位数的大小有关系。

  • 其次,在斐波那契数列中,我们通常是从头开始计算整个数列,然后逐步求得目标位置的值。而在此题中,我们只需要求出一个特定的数字对应的翻译方案数量,因此可以只遍历一遍输入数字的字符串,使用类似滚动数组的方式来更新当前位置能够翻译的方案数量以及前面两个位置的方案数量即可。

#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
    int translateNum(int num) {
        string s=to_string(num);
        int a=1,b=1,len=s.size();
        for(int i=1;i<len;i++){
            string tmp=s.substr(i-1,2);
            int c=tmp>="10"&&tmp<="25"?a+b:a;
            b=a;
            a=c;
        }
        return a;
    }
};
int main() {
    Solution so;
    int num,res;
    cin>>num;
    res=so.translateNum(num);
    cout<<res;
    return 0;
}

在这个代码中,变量a表示当前数字翻译成字母的方法数,b表示前一个数字翻译成字母的方法数。在循环中,我们需要根据当前的两个数字来判断是否可以将它们一起翻译成一个字母。如果可以,则c=a+b否则只能单独将第二个数字翻译成一个字母,c=a。

因为下一次循环的时候,当前的c会变成下一轮迭代的a,所以在不满足条件的情况下,a保持不变。而对于变量b,因为它表示前两个数字翻译成字母的方法数,所以它的值要更新为上一次循环中的a,即b=a。这样就可以保证每次循环中,a和b分别表示前一个数字和前两个数字翻译成字母的方法数,而c是根据当前的两个数字计算出来的新的方法数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖c个铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值