LeetCode 91.解码方法——动态规划

本文介绍了解码字符串问题的动态规划算法实现,详细解释了状态转移方程,并提供了两种不同空间复杂度的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目概述:

在这里插入图片描述

题解

  这个题其实建立动态规划的指标比较容易,很容易想到就是以第i个字符为结尾的解码方法数,但是难想的是状态转移方程,这里定义f(i)f(i)f(i)为以第i个字符结尾时的解码方法数。
  注意到一个新的字符加入前面的串后,有两种解码方式:一种是自己作为一个单独的字符解析,然后前面保留原来的解析方式,这种解码的要求是字符s[i−1]s[i - 1]s[i1]可以单独解析,也就是说s[i−1]!=′0′s[i-1] != '0's[i1]!=0,这种情况下,解码方法数就等于f(i−1)f(i -1)f(i1)
  另一种解码方法是以自己和前面一个字符为一个整体解码,这样解码的方法数等于以第i - 2个字符为结尾时串的解码数f(i−2)f(i - 2)f(i2),这里要和前一个字符整体解码,因此首先要求前一个字符不能是'0',因为题目规则规定了'06'这种解析方法是不合法的,另外,如果要这两个字符是一个有效合法解析,还要求这样两个字符组成的数字不大于26,超出26的话就不能解析为任何一个英文字母了。
  如果这两种方法都不能解析,说明以该字符结尾的串没有解析方法,由于vector容器在创建时,值默认初始化为0,所以除了这两种情况以外就不需要管了,直接就是0种方法。
代码:

class Solution {
public:
    int numDecodings(string s) 
    {
        int size = s.size();
        //f(i)表示以第i个字符结尾的串的解析方法数
        vector<int> f(size + 1);//第一个f[0]对应空字符串
        //f(0) = 1表明空字符可以解析成一个''只不过不能组合而已
        f[0] = 1;
        for (int i = 1; i <= size; ++i)
        {
            //第一种情况 最后一个字符自己解析 不和前面的字符结合
            //能解析的前提是它不等于'0'
            //这种情况的方法数等于(1,i-1)字符的解析数目
            if (s[i - 1] != '0')
            {
                f[i] += f[i - 1];
            }
            //第二种情况 用倒数两个字符解析
            //能解析的前提是倒数第二个字符不等'0'
            //这种方法数等于(i, i - 2)字符解析的方法数
            if (i > 1 && s[i - 2] != '0' && (s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)
            {
                f[i] += f[i - 2];
            }
        }
        return f[size];
    }
};

  注意到状态仅和f(i−1)f(i - 1)f(i1)f(i−2)f(i - 2)f(i2)有关,因此可以优化时间复杂度,用三个变量分别维护第i个字符的f(i),f(i−1),f(i−2)f(i),f(i - 1),f(i - 2)f(i),f(i1),f(i2),代码如下:

class Solution {
public:
    int numDecodings(string s) 
    {
        //a = f(i) b = f(i - 1) c = f(i - 2)
        int a = 0;//尚未计算
        int b = 1;
        int c = 0;//尚不存在
        int size = s.size();
        for (int i = 1; i <= size; ++i)
        {
            //先把 a清空 消上一轮计算的存留
            a = 0;
            //第一种情况 最后一个字符自己解析 只要它不等于'0'就可以自己解析
            if (s[i - 1] != '0')
            {
                a += b;
            }
            if (i > 1 && s[i - 2] != '0' && (s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)
            {
                a += c;
            }
            c = b;
            b = a;
            //其他情况都解析不出来字符,就不用管了 走一步a置成0 然后更新一下c和b就行了
        }
        return a;
    }
};

时间复杂度:O(n)O(n)O(n)
空间复杂度:O(1)O(1)O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值