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

题目链接:

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

题目描述:

LeetCode每日一题 | 91. 解码方法_第1张图片

思路解析:

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

我们以 2216 为例:

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

LeetCode每日一题 | 91. 解码方法_第2张图片

LeetCode每日一题 | 91. 解码方法_第3张图片

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

LeetCode每日一题 | 91. 解码方法_第4张图片

LeetCode每日一题 | 91. 解码方法_第5张图片

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

LeetCode每日一题 | 91. 解码方法_第6张图片 

LeetCode每日一题 | 91. 解码方法_第7张图片

此时我们就推出了 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 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];
    }
};

性能优化:

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

总结:

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

你可能感兴趣的:(LeetCode每日一题,leetcode,算法,职场和发展)