专栏首页racaljkLeetcode 91. Decode Ways 解码方法(动态规划,字符串处理)

Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理)

Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理)

题目描述

一条报文包含字母A-Z,使用下面的字母-数字映射进行解码

 'A' -> 1
 'B' -> 2
 ...
 'Z' -> 26

给一串包含数字的加密报文,求有多少种解码方式 举个例子,已知报文"12",它可以解码为AB(1 2),也可以是L (12) 所以解码方式有2种。

测试样例

Input:
"0"
"121212"
"101010"
"1001"
"0101"
Output:
0
13
1
0
0

详细分析

这道题不难,不过corner cases比较多,需要仔细分析。先考虑1212这个例子:(为了表达方便,我们用逗号分隔表示每种解码方式而不用扳手指算,比如1212的一种解码方式为12,12而不用L,L)

1=>

1

12=>

1,2
12

121=>

1,2,1
1,21
12,1

1212=>

1,2,1,2
1,21,2
12,1,2
1,2,12
12,12

到这里就可以总结出规律了,对于1212,其实是两种解码的和:

1,2,1,(2)
1,21,(2)
12,1,(2)
-----------
1,2,(12)
12,(12)

分割线上面是121的解码方式,并在后加以当前下标的2,分割线下面是12的解码方式加以当前下标和前一个下标表示的字符。

可以看出,如果当前字符和前面一个字符可以构成>10 && <=26(不包括20,至于为什么等下说)的字符,那么当前解码方式就是:

dp[i]=dp[i-1]+dp[i-2]

现在考虑一些corner case,如果当前字符是0,那么它并不符合上面的递推公式,考虑2020: 20=>

20

202=>

20,2

2020=>

20,(20)

可以看到2020,由于0不在解码范围内,所以它不能与前一项通过添加后缀的方式构成解码方式,它只是简单等于前两项然后加上后缀20,同理还有10。

按照这种思路,我们可以得出下面的状态转移:

let x = s.substr(i-1,2);
x>0 && x<10:    dp[i]=dp[i-1]
x==10:          dp[i]=dp[i-2]
x>10&&x<20:     dp[i]=dp[i-1]+dp[i-2]
x==20:          dp[i]=dp[i-2]
x>20&&x<=26:    dp[i]=dp[i-1]+dp[i-2]
x>26&&x%10!=0: dp[i]=dp[i-1];
x>26&&x%10==0: return 0

代码实现

代码太烂凑合看吧...

class Solution {
public:
    int numDecodings(string s) {
        if(s.length()==0){
            return 0;
        }
        if(s[0]=='0'){
            return 0;
        }
        if(s.length()==1){
            return 1;
        }
        int dp[100000];
        dp[0]=1;
        std::string ns = s.substr(0,2);
        int t = atoi(ns.c_str());

        if(t>0 && t<10){
            return 0;
        }else if(t==10){
            dp[1]=1;
        }else if(t>10 && t<20){
            dp[1]=2;
        }else if(t==20){
            dp[1]=1;
        }else if(t>20 && t<=26){
            dp[1]=2;
        }else if(t>26 && t%10!=0){
            dp[1]=1;
        }else{
            return 0;
        }
        if(s.length()==2){
            return dp[1];
        }

        for(int i=2;i<s.length();i++){
            std::string tempStr = s.substr(i-1,2);
            int n = atoi(tempStr.c_str());

            if((n>26 && n%10!=0)||(n>0 && n<10)){
                dp[i]=dp[i-1];
            }else if(n>10 && n<=26&& n!=20){
                dp[i]=dp[i-1]+dp[i-2];
            }else if(n==10 || n==20){
                dp[i]=dp[i-2];
            }else if(n==0 || n%10==0){
                return 0;
            }
        }
        return dp[s.length()-1];
    }
};

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Leetcode 931. Minimum falling path sum 最小下降路径和(动态规划)

    所谓下降路径是指,从一行到下一行,只能选择间距不超过1的列(也就是说第一行的第一列,只能选择第二行的第一列和第二列;第二行的第二列,只能选择第三行的第一列第二列...

    racaljk
  • Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力)

    racaljk
  • [动态规划] 矩阵链乘法问题

    矩阵链乘法问题是指给定一串矩阵序列M₁M2..Mn,求至少需要进行多少次乘法运算才能求得结果

    racaljk
  • 最长公共子串

    动态规划是大厂的热门考点,其中最长公共子串与最长公共子序列这两道题出现得尤其频繁,这两道题其实有挺多变种,很适合考察侯选人对动态规划的掌握情况,今天我们就先来看...

    kunge
  • HDU-4405-Aeroplane chess

    ACM模版 描述 ? 题解 概率 DPDP,求期望。 状态转移方程很容易想,设 dp[i]dp[i] 表示在位置 ii 还需要多少期望才能到达终点,那么 dp[...

    f_zyj
  • 动态规划:整数拆分,你要怎么拆?

    给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。返回你可以获得的最大乘积。

    代码随想录
  • 动态规划:爬楼梯

    所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。

    代码随想录
  • 动态规划:斐波那契数

    题目地址:https://leetcode-cn.com/problems/fibonacci-number/

    代码随想录
  • 打卡群2刷题总结1014——爬楼梯

    https://leetcode-cn.com/problems/climbing-stairs/

    木又AI帮
  • 打卡群2刷题总结1013——不同的二叉搜索树

    https://leetcode-cn.com/problems/unique-binary-search-trees/

    木又AI帮

扫码关注云+社区

领取腾讯云代金券