动态规划|【斐波那契数列模型 】|91.解码方法

目录

题目

题目解析

动态规划思路

1.状态表示

2.状态转移方程。

单独解码

成功

失败

i和i-1解码

成功

失败

3.初始化

4.填表顺序

5.返回值

代码


题目

91. 解码方法

一条包含字母 A-Z 的消息通过以下映射进行了 编码 :

'A' -> "1"
'B' -> "2"
...
'Z' -> "26"

要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

  • "AAJF" ,将消息分组为 (1 1 10 6)
  • "KJF" ,将消息分组为 (11 10 6)

注意,消息不能分组为  (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。

题目数据保证答案肯定是一个 32 位 的整数。

示例 1:

输入:s = "12"
输出:2
解释:它可以解码为 "AB"(1 2)或者 "L"(12)。

示例 2:

输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

示例 3:

输入:s = "06"
输出:0
解释:"06" 无法映射到 "F" ,因为存在前导零("6" 和 "06" 并不等价)。

提示:

  • 1 <= s.length <= 100
  • s 只包含数字,并且可能包含前导零

题目解析

        题目中说,对26个字母进行编码,然后给定一个纯数字的字符串要进行解码,解码也就是反过来用数字取对应字母,另外给出了一些规则,题目中要我们注意06不能映射成F,6可以映射成F。要求返回数字解码方法的总数。

动态规划思路

1.状态表示

        创建一个dp表,题目要求从左往右,进行解码,所以dp表一定是一个一维数组,根据前面文章里面的题目,我们状态表示一般使用以i位置为起点或者以i位置为终点,这里我们使用以i位置为终点,题目问,解码方式,所以dp[i]就表示从0位置到i位置的解码方式。

2.状态转移方程。

      要表示dp[i],i位置的解码有两种方式,一种是单独解码,一种是i和i-1解码然后再加上前i-1位置的解码方式,我们先分析前两种方式的解码

单独解码

成功

i位置的数是1到9,从0到i-1位置的解码总数方式的表示根据状态表示得出就是dp[i-1],i位置单独解码成功就是,在前面那些解码后的串后面统一加一个字符,结果显而易见还是dp[i-1]种,所以这种情况的状态转移方程dp[i]=dp[i-1]

失败

i位置的数是0,如果最后一个不能解码,就说明前面的解码的全部失败,因为我要的整个的解码方式,不是局部的解码方式,所以只要最后一个不能解码就会导致整个数字串解码失败,dp[i]=0

i和i-1解码

成功

这个两个组合成一个两位数解码,因为题目中说06不能解码,说明想要成功解码这个两位数必须是10到26的(包含10和26),同理i和i-1解码成功,相当于在从0到i-2位置解码方式后面同一加上一个i和i-1解码出来的字符,结果还是dp[i-2]种,dp[i]=dp[i-2].

失败

同理,一个解码失败,整个数字串都不会成功dp[i]=0

总的解码情况,应该是单独解码成功的情况加上组合解码成功的情况所以dp[i]=dp[i-1]+dp[1-2]

3.初始化

之前说过初始化就是为了填表的时候不越界,算i位置的时候要用到i-1和i-2所以我们要初始化dp[0]和dp[1],

dp[0]:表示只有一个数字,这个数字是0的话就解码失败也就是dp[0]=0,这个数字是1到9 的时候解码成功也就是dp[0]=1

dp[1]:表示有两个数字,两个数字的话就可以单独解码或者组合解码,第一种分别单独解码(两个都是1到9)的数字,第二种就是两个数字组合也可以解码

如果这两种都不可以解码,dp[1]=0

这两个只有一个可以解码,dp[1]=1

这两个都可以解码,dp[1]=2

4.填表顺序

求dp[i]的时候要先知道dp[i-1]和dp[i-2],所以很明显填表顺序是从左往右

5.返回值

返回值,看状态表示就行返回dp[s.length-1]

代码

知道字符数字,要向组合还得减去‘0’,比如 整形5=字符5-字符0->5='5'-'0'

int numDecodings(char* s)
{
   int n =strlen(s);
    //创建dp表
    int dp[1000] = { 0 };
    //初始化
    if(s[0]!='0')dp[0]+=1;
    if(n==1)return dp[0];
    if(s[0]!='0'&&s[1]!='0')dp[1]+=1;
    int t=(s[0]-'0')*10+s[1]-'0';
    if(t>=10&&t<=26)dp[1]+=1;
    //边界

   //if(n==2)return dp[1];
    //填表
   for(int i=2;i<n;i++)
   {
       //第一种情况就是可以单独编码
       if(s[i]!='0')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];
}

时间复杂度:O(n)

空间复杂度:O(n)

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值