【动态规划篇】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. 状态表示
    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]

代码实现:

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,第二个字符与第一个字符共同解码时的方法总数应该为2dp[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];
    }
};
相关推荐
七牛云行业应用1 天前
深度解析强化学习(RL):原理、算法与金融应用
人工智能·算法·金融
和编程干到底1 天前
数据结构 栈和队列、树
数据结构·算法
纪元A梦1 天前
贪心算法在GNN邻域采样问题中的深度解析
算法·贪心算法
宇钶宇夕1 天前
西门子 S7-200 SMART PLC 核心指令详解:从移位、上升沿和比较指令到流水灯控制程序实战
运维·算法·自动化
爱编程的化学家1 天前
代码随想录算法训练营第十一天--二叉树2 || 226.翻转二叉树 / 101.对称二叉树 / 104.二叉树的最大深度 / 111.二叉树的最小深度
数据结构·c++·算法·leetcode·二叉树·代码随想录
tqs_123451 天前
redis zset 处理大规模数据分页
java·算法·哈希算法
吃着火锅x唱着歌1 天前
LeetCode 1446.连续字符
算法·leetcode·职场和发展
愚润求学1 天前
【贪心算法】day10
c++·算法·leetcode·贪心算法
吴秋霖1 天前
主流反爬虫、反作弊防护与风控对抗手段
爬虫·算法·反爬虫技术
java1234_小锋1 天前
Scikit-learn Python机器学习 - 分类算法 - K-近邻(KNN)算法
python·算法·机器学习