动态规划(4)斐波那契数列模型——解码方法

大家好呀,这是斐波那契数列模型的最后一道题了,那我们话不多说,先看一下题目吧

一、题目解析

题目对字符A~Z进行了编码,分别对应的是字符"1~26",然后给了我们一个字符串,字符串是由"1~26"组成,要求我们对这个字符串进行解码,然后返回解码方法的总数。我们还是具体看一个示例 吧。

示例1:给了我们一个字符串“12”,它可以每个字符单独解码,就是"AB",1解码为字符A,2解码为字符B,然后也可以组合解码为一个单独的"L"(12)。因此返回解码方法数"2"。

然后再看一下示例3吧,示例3是不能解码的,因为是存在前导0的,"6"和“06”是不等价的。因此返回解码方法数0。

相信大家看了上面两个例子已经明白题目要求了,接下来就分析一下这道题应该如何做吧。

二、算法原理

1、状态表示:

我们先来看状态表示,状态表示是有规律可循的,一般我们都是根据经验+题目要求来定义状态表示的,题目要我们求解码方法的总数,那我们就定义吧。

dp[i]表示:以i位置为结尾,此时的解码方法总数。那么这个状态表示对不对呢?我们如果可以推出来状态转移方程就是对的。

2、状态转移方程:

状态转移方程也是有规律可循的,一般是根据它最近的一步来划分问题,状态表示是i位置为结尾,那我们来考虑一下解码到i位置的时候,这个时候有两种情况。

情况一:s[i]字符单独解码

s[i]可以单独解码:

s[i]在1~9之间就可以单独解码,那么解码成功总解码数是多少呢?是不是dp[i - 1]呀,dp[i-1]表示什么?以i-1位置为结尾的解码方法总数,那么我们在每一种方法后面再跟上s[i]是不是就可以了?注意,这里不是+1,因为它问的是解码方法的总数,一定要想清楚这一点。

s[i]无法单独解码:

第二种情况就是s[i]单独解码不了,什么时候解码不了?0的时候呀,此时总方法数是多少?就是0呀,只要有一个字符解码不了,不管你前面解码的多好,都没用。

情况二:s[i]和s[i-1]组合起来一起解码

s[i]和s[i-1]可以解码:

只要 10 <= s[i - 1] * 10 + s[i] <= 26 就可以解码,这里为什么不是大于等于1小于等于26呢?大家思考一下,因为是不能有前导0的呀。此时的总解码方法数是多少呢? 是不是dp[i - 2]呀?我们在dp[i-3]每一种方法的基础上再多加一步s即可。这里如果不理解的一定要去看搞明白状态表示是什么含义,如果你看不懂状态转移方程大概率是你没理解状态表示。

s[i]和s[i-1]无法解码:

无法解码的方法数就是0。

那么,dp[i]是不是就是把这两种情况都加起来呀,dp[i] = dp[i - 1] + dp[i - 2],但是这里一定要判断,你能不能解码,如果你不能解码你就不可以加上对应的方法数。因此我在下面的图里面状态转移方程打了两颗五角星。不要无脑就直接开加。

3、初始化:

我们填i位置的时候可能是会用到i-1和i-2位置的,因此我们必须初始化前两个位置,我们先看第一个位置,如果第一个字符可以解码那么它的解码方法数就是1,因此dp[0]初始化为1,如果不能解码你还搞啥呢?直接返回结果0就行了。然后看第二个字符,第二个字符我们需要判断它自己能不能单独解码,能不能和前一个字符组合起来解码,如果它可以单独解码,并且它和前一个字符可以组合起来解码,dp[1]就初始化为2,如果它不能组合解码只能单独解码就初始化为1,如果都不能单独解码,你别玩了,直接返回结果0即可。如何判断它和前一个字符可不可以组合解码呢?不用我说了吧,上面已经说过了。

4、填表:

因为你要用到前两个位置的状态,因此是从左往右填表。

5、返回值:

返回最后一个位置dp[n- 1]即可。

三、编写代码

希望大家可以根据算法原理自己尝试编写一下代码。

class Solution 
{
public:
    int numDecodings(string s) 
    {
        int n = s.size();
        //1.创建一个dp表
        vector<int> dp(n);
        //2.初始化
        if(s[0] == '0') return 0;//如果是0表明无法解码,直接返回0
        dp[0] = 1;
        if(n == 1) return dp[0];

        if(s[1] >= '1' && s[1] <= '9') dp[1]++;
        int t = (s[0] - '0') * 10 + s[1] - '0';
        if(t >= 10 && t <= 26) dp[1]++;

        for(int i = 2; i < n; i++)
        {
            if(s[i] >= '1' && s[i] <= '9') dp[i] += dp[i - 1];
            int t = (s[i - 1] - '0') * 10 + s[i] - '0';
            if(t >= 10 && t <= 26) dp[i] += dp[i - 2];
        }

        return dp[n - 1];

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值