Leetcode 91. 解码方法

91. 解码方法

可以访问我的博客,吼吼

题目表述

一条包含字母 A-Z 的消息通过以下方式进行了编码:
‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:
输入: “12”
输出: 2
解释: 它可以解码为 “AB”(1 2)或者 “L”(12)。
示例 2:
输入: “226”
输出: 3
解释: 它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-ways
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

还是利用动态规划。但与上一题最长回文子串不同的是,这道题的状态转移方程不一样,但都差不多。观察状态转移方程发现,可以将二维的数组压缩到一维。最后总结一下常见的状态转移方程的形式
ps.弱弱地说一句,其实上一题也是可以优化,由 m × n m\times n m×n维变成 2 × n 2\times n 2×n维的。

下面开始吧

d p [ i ] [ j ] dp[i][j] dp[i][j]表示字符串 s [ i : j ] s[i:j] s[i:j]编码的最大方案数。

状态转移方程:

d p [ i ] [ j ] = m a x { d p [ i ] [ j − k − 1 ]   ∣   1 ≤ s [ j − k : j ] ≤ 26 , 0 ≤ k ≤ m i n { 2 , j − i + 1 } } dp[i][j]=max\{dp[i][j-k-1]\ |\ 1\leq s[j-k:j]\leq 26,0\leq k\leq min\{2,j-i+1\} \} dp[i][j]=max{dp[i][jk1]  1s[jk:j]26,0kmin{2,ji+1}}
我试着说明一下。
假设 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1]已经知道了,也就是说字符串 s [ i : j ] s[i:j] s[i:j]的编码方案数已知,现在考虑地第 j j j位字符。需要做的是,选择从 j j j位往前,选择 k k k位字符,将它们跟第 j j j位拼起来并看成一个整体,也就是将 s [ i : j ] s[i:j] s[i:j]分成 s [ i : j − k − 1 ] s[i:j-k-1] s[i:jk1] s [ j − k : j ] s[j-k:j] s[jk:j]两个部分,注意,这样分的前提是 s [ j − k : j ] s[j-k:j] s[jk:j]是可编码的,也就是对应着 1 ≤ s [ j − k : j ] ≤ 26 1\leq s[j-k:j]\leq 26 1s[jk:j]26这个条件。举个例子, s = 226 s=226 s=226,现在考虑 6 6 6这一位,如下图:

这是两种不同的方案,然后去这两中方案中的最大那一种就可以,也就是对应着公式中 m a x { d p [ i ] [ j − k − 1 ] } max\{dp[i][j-k-1]\} max{dp[i][jk1]}的部分。
因为从1到26,最大就是2位数,所以 k k k最大是1,也就是最多往前选1个字符,又因为还需要保证 s [ i : j − k − 1 ] s[i:j-k-1] s[i:jk1]不为空,所以需要 i ≤ j − k − 1 i\leq j-k-1 ijk1,即 k ≤ j − i + 1 k\leq j-i+1 kji+1,这就对应了公式中 0 ≤ k ≤ m i n { 2 , j − i + 1 } 0\leq k\leq min\{2,j-i+1\} 0kmin{2,ji+1}的部分。

然后说一下空间优化的问题。

从上面的状态转移方程可以看出,求 d p [ i ] [ j ] dp[i][j] dp[i][j]只需要第 i i i j j j左边的元素就行,用不着其他行的元素,所有可以二维降成一维。

降为一维后,还是进行跟原来类似的操作,只不过就是对这一维数组进行了多次操作,如下图。

优化之后的状态转移方程就变成了:
d p [ j ] = m a x { d p [ j − k − 1 ]   ∣   1 ≤ s [ j − k : j ] ≤ 26 , 0 ≤ k ≤ m i n { 2 , j − i + 1 } } dp[j]=max\{dp[j-k-1]\ |\ 1\leq s[j-k:j]\leq 26,0\leq k\leq min\{2,j-i+1\} \}\\ dp[j]=max{dp[jk1]  1s[jk:j]26,0kmin{2,ji+1}}
其中 i i i表示当前是第几次操作。

下面总结一下常见的状态转移形式,方程就不写了,记不住,就把图画一画吧。

紫色五角星表示要求的目标,蓝色表示求这个目标需要那些元素
第一类:

第二类:

第三类:

代码实现

class Solution {
public:
    int numDecodings(string s) {
        if (s.length() <= 0) return 0;
        
        set<string> se {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", 
                       "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", 
                       "21", "22", "23", "24", "25", "26"};
        int dp[3050] = {0};
        for (int i = 0; i < s.length(); i++) {
            if (s[i] != '0') {
                dp[i] = 1;   
            }
        }
        int m = s.length();
        for (int t = 1; t < m; t++) {
            int i, j;
            i = m - t - 1;
            for (j = i+1; j < m; j++) {
                int cur = 0;
                for (int k = 0; k <= min(1, j-i+1); k++) {
                    if (se.find(s.substr(j-k, k+1)) != se.end()) {
                        if (j - k - 1 < i) {
                            cur += 1;
                        }
                        else
                            cur += dp[j-k-1];
                    }
                }
                dp[j] = cur;
            }
        }
        return dp[m-1];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值