剑指offer---把数字翻译成字符串
Posted 可乐不解渴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer---把数字翻译成字符串相关的知识,希望对你有一定的参考价值。
🌏生活有望穿水的期待,也会有意想不到的惊喜。
题目描述
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5 解释: 12258
有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”,"mcfi"和"mzi"
题目链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof
解题思路
我们以上面的示例12258为例来分析一步步的进行翻译。
①首先我们从第一位1开始翻译,此时我们有两种翻译方法。第一种是将1翻译成b,后面就剩下2258,第二种是将第一位和第二位进行结合成12翻译成m,此时就剩下258;
②接着我们继续翻译下一个字符2,第一种将2翻译成c,此时剩下258,第二种将第二位和第三位进行结合成22翻译成w,此时剩下58;
③继续进行与2相同的操作,第一种将第三位的2翻译成c,剩下58,第二种将第三位的2与第四位的5进行结合翻译成z,剩下8;
④我们继续翻译5,此时只有一种翻译方法,那就是将5翻译成f,剩下一个8;
⑤最后翻译最后一个字符8,此时结束。
在上面的操作中我们可以很简单的就写出一个递归方程来解决这个问题,我们定义函数f(i)表示从第i位开始的不同翻译的数目,此时那么我们的递归方程就为f(i)=f(i+1)+g(i,i+1)×f(i+2)。上面那个g(i,i+1) 表示的是当前数字能否与下一个数字进行结合形成另外一种的翻译方式的一个状态函数。如果可以结合进行翻译则为true,否则为false。
动态规划
在上面的代码中,虽然我们可以这样用递归的方式来进行书写代码,但我们发现有许多的重复计算的子问题。那我们怎么去消除这些子问题呢?遇到这种出现重复子问题的题目一般我都要去往动态规划上面去想。
那么如何进行动态规划呢?
1、化成子问题,在上面我们已经将其化为子问题。
2、确定状态转移方程
那么我们如何确定状态状态方程呢?
根据上面的子问题那么我们可以归纳出翻译的规则:
我们可以定义dp[ i ] 表示前 i 个数字的翻译方法数。
例:dp[2]代表前2个数字的翻译方法。
所以数组的长度要初始化为字符串的长度加一,这样才能表示到最后一个数字的索引。
最后一个元素dp[3]则能表示前3个数字的翻译方法,也就是整个数字的翻译方法。
如果第 i - 1位和第 i 位组成的数字在 [10,25]之间,可以把这两位连起来翻译,则dp[i] = dp[i - 1]+dp[i-2]。
如果第 i 个数字只能自己单独翻译,不能和第i-1个数字组合翻译成字母的话,则dp[i] = dp[i - 1]。
该题的状态转移方程如下:
{ combine>=10&&combine<=25 dp[i]=dp[i-1]+dp[i-2]
确定转移方程为:dp(i)= {
{ combine<10&&combine>25 dp[i]=dp[i-1]
这题就和青蛙跳台阶一样,只是在它的基础上加了一个范围限制。
3、确定开始和边界
我们需要将dp[0]与dp[1]这个位置赋予初值1,即dp[0]=1,dp[1]=1。
4、计算顺序
dp[0]、dp[1]、dp[2]…dp[n+1]。
解题代码
class Solution
{
public:
int translateNum(int num)
{
string numstirng=to_string(num); // 将数字转化成字符串
int len=numstirng.size();
vector<int>dp(len+1,0);
// 当前两个数字能组合翻译时,dp[2] = dp[1] + dp[0],
// 结果应该是2,dp[1]已知等于1,所以dp[0]也等于1
// 如果前2个数不能组合翻译时,那么dp[2]=dp[1]
dp[0]=1;
dp[1]=1;
/*
注意:这个循环的i代表的是动态规划数组的索引
也就是说,i表示的是数字字符串中第i-1个数字
因为第一个数字明显只有一种翻译方法,所以从第二个数字开始遍历字符串
*/
for(size_t i=2;i<dp.size();++i)
{
/*判断当前遍历到的数字(索引i-1)能否和前一个数字(索引i-2)组合起来翻译
只有当两个数字组合起来在[10,25]区间时才可以一起翻译
*/
int curdigit=numstirng[i-1]-'0';
int prevdigit=numstirng[i-2]-'0';
int combine=curdigit+prevdigit*10;
if(combine>=10&&combine<=25)
{
dp[i]=dp[i-1]+dp[i-2];
}
else
{
dp[i]=dp[i-1];
}
}
// 动态规划数组最后一个元素即是整个数字的所有翻译方法个数
return dp[len];
}
};
如有错误之处或有更优解,还请各位指出,谢谢大家!!!
END…
以上是关于剑指offer---把数字翻译成字符串的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode(剑指 Offer)- 46. 把数字翻译成字符串