LeetCode每日一题 | 91. 解码方法

题目链接:

91. 解码方法 - 力扣(LeetCode)

题目描述:

思路解析:

这道题乍一看好像没有什么思绪,好像没有很明显的推导的过程,也没有很明显的状态变化。但是题目中给了我们数字不同的组合方式,我们发现一个数字要么自己解码,要么和它前面的一个数字组合在一起解码(为什么没有和后面一个数字一起呢,因为对于后面一个数字,它不就是和它前面的数字结合吗,这样不就都是和前面的数字组合吗),我们发现了它的两种解码方法

我们以 2216 为例:

我们对数字 6 进行第一种情况的处理:单独编码

我们再以第二种情况进行处理:组合编码

然后我们以 i 状态为例,我们来进行进一步的解析:

 

此时我们就推出了 i 位置的编码方式总和,它与前面的编码方式总和息息相关,我们不难看出这是一个递推的过程

这样,我们就可以列出状态转移方程:

  • 第一种情况是我们使用了一个字符,即 s[i]进行解码,那么只要 s[ i ] ≠ 0,它就可以被解码成 A∼I 中的某个字母。由于剩余的前 i−1个字符的解码方法数为 dp (i-1) 因此我们可以写出状态转移方程:

dp ( i ) = dp( i -1),其中 s[ i ] ≠ 0

  • 第二种情况是我们使用了两个字符,即 s[ i − 1 ]和 s[ i ]进行编码。与第一种情况类似,s[ i −1 ]不能等于 0,并且s[ i − 1 ] 和 s[ i ]组成的整数必须小于等于 26,这样它们就可以被解码成 J∼Z中的某个字母。由于剩余的前 i−2字符的解码方法数为 dp( i - 2 ),因此我们可以写出状态转移方程:

dp( i ) = dp( i - 2 ),其中 s[ i − 1] ≠ 0 并且 10⋅s[ i − 1 ] + s[ i ] ≤ 26

需要注意的是,只有当 i > 1时才能进行转移,否则 s[ i − 1 ]不存在。

代码:

class Solution {
public:
    int numDecodings(string s) 
    {   
        //建dp表
        int n = s.size();
        vector<int> dp(n);
        dp[0] = s[0]!='0';

        //初始化
        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;
        //填表
        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];
    }
};

性能优化:

对于这里不断递推的题,我们可以采用滚动数组的思想进行性能优化

总结:

对于这种下一步结果依赖上一步结果的题目,根据不断的递推来求解的问题,我们可以根据中间态找出它的状态转移方程,然后从原点开始先进行初始化然后根据条件进行一步接一步的递推关系求解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值