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

题目概述:

LeetCode 91.解码方法——动态规划_第1张图片

题解

  这个题其实建立动态规划的指标比较容易,很容易想到就是以第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)

你可能感兴趣的:(LeetCode刷题,动态规划,leetcode,算法)