2021-11-14 leetcode 动态规划 91.解码方法 c++

题目

leetcode 91.解码方法
请添加图片描述
In a brief: 将一串数字拆按不同方式拆分,但拆分后的个体的值的区间为1~26,求总拆分方法数。

思路

动态规划

定义

已知:字符串str[0…i…n]
dp[i] :对于str[0…i]的字符串,所得解码的总数

求dp[i]

首先分析str[i],可能值为:‘0’, ‘1’, ‘2’
解码总数取决于str[i]不同的取值,因此,对str[i]进行分类讨论:

i) str[i] == '0’
只有一个字符 '0’时,无法单独被解码。需要联系前面的一个字符。
当str[i - 1] == ‘1’ 或 '2’时,str[I - 1] + str[I] 为 ‘10’ 或 ‘20’,此时能唯一被解码。str[0…I-2]可能有不同的拆分方法,str[i - 1] + str[I] 只能放在一起组合。因此,str[0…i]的解码方法数与str[0…i-2]解码方法数一致,即 dp[i] = dp[i - 2]

ii)str[i] == ‘1’ 或 '2’
此时拆分方法有两种情况:
1: 单独对str[I]解码,则唯一被解码,dp[i] = dp[i -1]

2: 与前一项组合解码,则需要对str[i - 1]进行判断,只有当str[i - 1] == ‘1’ 或 '2’时,str[i] + str[i - 1] 才是符合题意的两位数,才能组合解码。
合并解码的数字能被唯一解码,则解码方法数与str[0…i-2]的解码方法数相同。即dp[i] = dp[i - 2]
若str[i - 1] == ‘1’ 或 ‘2’,此时既可以单独解码也可以组合解码, dp[i] = dp[i -1] + dp[i -2]
注意:当str[I - 1] = '2’时,str[I]的区间为[0,6]

对ii)中的1,2进行总结:
str[I - 1] == ‘1’ 或’2’时,可以组合或者单独解码,dp[i] = dp[i -1] + dp[i -2]
str[I - 1] =='0’时,只能单独解码,dp[i] = dp[i -1]

初始化

若str[0] != 0
dp[0] = 1

解题代码

本来代码是

class Solution {
public:
    int numDecodings(string s) {
        if(s[0] == '0')
            return 0;
        int n = s.size();
        int dp[n];
        dp[0] = 1;
        for(int i = 1; i < n; i++) {
            if(s[i] == '0') {
                if(s[i - 1] == '1' || s[i - 1] == '2')
                    dp[i] = dp[i - 2];
                else
                    return 0;
            }
            else {
                if(s[i - 1] =='1' || s[i - 1] == '2' && s[i] > '0' && s[i] <= '6')//可以组合解码或者单独解码
                    dp[i] = dp[i - 1] + dp[i - 2];
                else//只能单独解码
                    dp[i] = dp[i - 1];
            }
        }
        return dp[n - 1];
    }
};

但是在计算dp[1] = dp[1 - 1] + dp[1 - 2] = dp[0] + dp[-1]时,无法计算dp[-1],则将所有数往后移一位,即 i = i +1,变成dp[i + 1] = dp[i] + dp[i - 1],就能进行计算了。

AC代码

class Solution {
public:
    int numDecodings(string s) {
        if(s[0] == '0')
            return 0;
        int n = s.size();
        int dp[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 1; i < n; i++) {
            if(s[i] == '0') {
                if(s[i - 1] == '1' || s[i - 1] == '2')
                    dp[i + 1] = dp[i - 1];
                else
                    return 0;
            }
            else {
                if(s[i - 1] =='1' || s[i - 1] == '2' && s[i] > '0' && s[i] <= '6')
                    dp[i + 1] = dp[i] + dp[i - 1];
                else
                    dp[i + 1] = dp[i];
            }
        }
        return dp[n];
    }
};

注意:dp[1]在这里的意义才是str[0]的解码数
dp[0]是为了状态转移方程的计算而产生,也是为什么将i都向后移一位的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

聪明的Levi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值