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

发布于:2025-03-21 ⋅ 阅读:(13) ⋅ 点赞:(0)

在这里插入图片描述
在这里插入图片描述

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. 状态表示
    dp[i]表示:以i位置为结尾时,所有解码方法的总数
  2. 状态转移方程
    根据最近的一步,划分问题
    在这里插入图片描述
    其中a表示s[i]位置的数,b表示s[i-1]位置的数
    dp[i] = dp[i-1] + dp[i-2]
  3. 初始化
    保证填表时不越界
    0位置结尾时说明此时只解码了一个字符
    在这里插入图片描述
    1位置结尾时说明此时解码了两个字符
    在这里插入图片描述
  4. 填表顺序
    从左向右
  5. 返回值
    dp[n-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];
    }

细节优化:
处理边界问题以及初始化问题的技巧

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

代码实现:

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];
    }
};