【动态规划篇】91. 解码方法


91. 解码方法

题目链接: 91. 解码方法
题目叙述: 一条包含字母 A-Z 的消息通过以下映射进行了 编码 :

"1" -> 'A'

"2" -> 'B'

...

"25" -> 'Y'

"26" -> 'Z'

然而,在解码已编码的消息时,你意识到有许多不同的方式来解码,因为有些编码被包含在其它编码当中("2" 和 "5" 与 "25")。

例如,11106可以映射为:

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

消息不能分组为 (1, 11, 06) ,因为 "06" 不是一个合法编码(只有 "6" 是合法的)。

注意,可能存在无法解码的字符串。

给你一个只含数字的 非空 字符串 s,请计算并返回 解码 方法的 总数 。如果没有合法的方式解码整个字符串,返回 0。

题目数据保证答案肯定是一个 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 只包含数字,并且可能包含前导零。


💦 前提注意: 这道题的s是一个非空字符串,而不是数组,所以计算时应减去'0'
解题思路:

  1. 状态表示
    dpi表示:以i位置为结尾时,所有解码方法的总数
  2. 状态转移方程
    根据最近的一步,划分问题

    其中a表示s[i]位置的数,b表示s[i-1]位置的数
    dpi = dpi-1 + dpi-2
  3. 初始化
    保证填表时不越界
    以0位置结尾时说明此时只解码了一个字符

    以1位置结尾时说明此时解码了两个字符
  4. 填表顺序
    从左向右
  5. 返回值
    dpn-1

代码实现:

cpp 复制代码
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];
    }

细节优化:

处理边界问题以及初始化问题的技巧

  • 我们可以开一个比旧的表多1个的新的dp表,使得旧dp表下标为0的位置,映射到新的dp表下标为1的位置,旧的下标为1的位置映射到新的下标为2的位置...依次类推。
  • 这样以来dp[i]就可以表示为以第i个字符为终点的解码方法的个数。所以就只需要初始化第1的字符即可。
  • 这里有个小细节,我们在初始化dp[0]这个虚拟节点时要将它初始化成1,比如只有两个字符我们要判断时 ,第二个字符单独解码时的方法数为1,第二个字符与第一个字符共同解码时的方法总数应该为2,dp[2] = dp[1] + dp[0],我们可以将dp[0]给反推出来,所以dp[0]应该初始化为1

代码实现:

cpp 复制代码
class Solution {
public:
    int numDecodings(string s) {
        //创建dp表
        //初始化
        //填表
        //返回值

        int n = s.size();
        //创建dp表
        vector<int> dp(n+1);
        dp[0] = 1;
        dp[1] = s[0] != '0';
        for(int i = 2;i <= n;i++)
        {
            if(s[i-1] != '0') dp[i]+=dp[i-1];
            int b = 10*(s[i-2]-'0') + (s[i -1] - '0');
            if(b>=10 && b <= 26) dp[i]+=dp[i- 2];
        }
        return dp[n];
    }
};
相关推荐
hetao17338371 小时前
2026-09-29 hetao1733837 的刷题记录
c++·算法
欣欣之王来了1 小时前
AI合规专项:AI算法透明度的合规要求
人工智能·算法
wzdark1 小时前
分块思想在算法优化中的实践与应用4
算法
Because_of_Her12 小时前
dfs-洪水填充技巧
笔记·算法·深度优先·洪水填充
小静AI工程实验室2 小时前
RSA 算法详解:从模幂原理到 OAEP 加密、PSS 签名与 Python 实验
python·算法
xzal122 小时前
GESP Python笔记
笔记·python·算法
wzdark2 小时前
算法中的记忆化思想与重复子问题优化4
算法
Discipline10292 小时前
流水线运行是否正随时间变得更加集中?
算法
lzhdim3 小时前
C#不为人知的10个魔法特性:资深开发者也会震惊的底层奥秘
java·前端·javascript·算法·c#
weixin_307779133 小时前
C++代码实现MATLAB中的pade函数功能
开发语言·c++·算法·matlab