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)。

题意

输入的数字是字符串,也就是说输入可能会包含0~9,但是编码方式并没有给出0的单独编码,所以当输入的字符串包含0的时候,需要作特殊的考虑。

当输入字符串没有0时

从简单入手,也就是没有0混在输入字符串中的时候,带0的稍后考虑。

动态规划的问题往往需要一步步推演,才能较快的找到前后关系,下面以"1221"输入为例,开始推演:

  • “1” :返回1,解码方式只有“A”
  • “12” :返回2,解码方式有“AB”(1 2),“L”(12)
  • “122” :返回3,解码方式有“ABB”(1 2 2),“LB”(12 2),“AV”(1 22)
  • “1221” :返回5,解码方式有“ABBA”(1 2 2 1),“LBA”(12,2,1),“AVA”(1,22,1),“ABU”(1,2,21),“LU”(12,21)

当时我自己做的时候,想到的输入是"12213",推过之后才发现了规律,可能比较笨。。。

光看前2个输入可能看不出什么。

  • 看输入为“122”的时候,比原先的输入“12”新增加了一个‘2’,看看增加后相对于原来“12”的输入,解码方式的总数是怎么发生改变的。

    增加了‘2’之后,从原先的2种方式变到3种方式。

    前两种方式“ABB”(1 2 2),“LB”(12 2)都是在原本“AB”(1 2),“L”(12)的基础上增加了一个解码‘2‘得到大写字母‘B‘,并没有增加解码方法。促使增加的原因是新增的‘2‘能与前一个位置的’2‘合并成‘22‘,即解码成字母‘V‘,因此多了新的一种解码方式“AV”。

    这样看来,后一个位置上的解码总数确实与之前位置的解码总数有一定的关系,现在还不能明确的说到底是如何。

  • 看第4组,在"122"的基础上增加了‘1’。
    • 以之前的思路考虑,“122”原本的解码方式为“ABB”(1 2 2),“LB”(12 2),“AV”(1 22),新增了‘1‘,如果不与前面位置的‘2‘合并的话,那么不增加解码总数,仍旧为3,解码方式变为“ABBA”(1 2 2 1),“LBA”(12,2,1),“AVA”(1,22,1);
    • 如果与前面位置的‘2‘绑定的话变成‘21‘,解码为‘U’,现在后两个数已经绑定了,也就是问输入“12(21)”有几种方式,因为解码的方式只可能是数字两位数[1-26],所以‘21’不可能与前面位置的‘2’绑定,这么看来,“12(21)”的解码总数与“12”的解码总数无异。

    而“12”的解码总数之前是有记录过的,“AB”(1 2),“L”(12),加上‘U‘后变为“ABU”(1,2,21),“LU”(12,21)。

    所以看来输入为“1221” 时,解码方式有“ABBA”(1 2 2 1),“LBA”(12,2,1),“AVA”(1,22,1),“ABU”(1,2,21),“LU”(12,21),一共有5种。假设当前位置为i,那么如果位置i的数字能与位置i-1的数字合法绑定[10-26]的话。

    dp[i] = dp[i-1] + dp[i-2]; dp[i]代表位置i的解码总数

  • 说到合法绑定,假如我的输入是“1228”,显然,“28”不是合法的,不能被解码。那么解码总数应该就等于“122”的解码总数。可以自行推演一下。

现在总结字符串无0输入是的状态转移方程:

# 位置i的解码总数为dp[i]
if 位置i 与 位置i-1 能合法绑定:
    dp[i] = dp[i-1] + dp[i-2];
else
    dp[i] = dp[i-1]

关于0

一开始我以为输入"01"是合法的,因为我觉得可以解码成‘A‘。后来提交后报错,我才意识到想当然了。当位置i出现‘0‘时,一定要考究i-1位置上的字符,下面举几个例子:

  1. ‘10‘ - 输入是合法的,因为0可以和前面的1绑定在一起,得到10,解码为"J",返回值为1
  2. ‘100‘ - 输入不合法,无法解码,无论是(1 0 0)(1 00)(10 0)(100)都是不合法的,返回为0
  3. ‘01‘ - 输入不合法,无法解码,这正是我之前想当然所犯的错误

有0输入情况

  1. 如果0在第一个输入,由于0无法被解码,所以返回解码总数0.
  2. 连续两个00出现肯定无法被解码,所以返回解码总数0
  3. 当前位置i出现0,必须要与i-1位置的数绑定,绑定不成功,返回0;绑定成功,位置i的解码总数与位置i-2相同。这个推导其实在上面绿字部分出现过,可以回去看看理解下。

代码

class Solution {
public:
    int numDecodings(string s) {
        // 边界条件:s为空;第一个输入为0;输入字符串长度为1
        if(s.size() == 0 || s[0] == ‘0‘)
            return 0;
        if(s.size() == 1)
            return 1;

        // parameters
        int len = s.size();
        int dp[len];
        dp[0] = 1;

        // 考虑第2个位置的解码总数的可能情况
        if(s[1] == ‘0‘ && (s[0] - ‘0‘) * 10 > 20)
            return 0;
        else if(s[1] == ‘0‘ && (s[0] - ‘0‘) * 10 <= 20)
            dp[1] = 1;
        else if(s[1] != ‘0‘ && (s[0] - ‘0‘) * 10 + s[1] - ‘0‘ > 26)
            dp[1] = 1;
        else
            dp[1] = 2;

        for(int i = 2; i < len; i++)
        {
            //判断的情况颇多,但是最重要的是当出现0时,它能否与前面出现的数字绑定为一个[1,26]内的合法数字,如果不能,返回0;否则,等于dp[i-2]

            //出现连续2次的0,直接返回0
            if(s[i] == ‘0‘ && s[i-1] == ‘0‘)
                return 0;

            else if(s[i] == ‘0‘ && s[i-1] != ‘0‘)
            {
                int t = (s[i-1] - ‘0‘) * 10;
                if(t > 20)                  // 不能绑定,直接返回
                    return 0;
                else                         // 可以绑定
                    dp[i] = dp[i-2];
            }

            else if(s[i] != ‘0‘ && s[i-1] != ‘0‘)
            {
                int t = (s[i-1] - ‘0‘) * 10 + s[i] - ‘0‘;
                if(t > 26)
                    dp[i] = dp[i-1];        // 不能绑定,等于前面位置
                else
                    dp[i] = dp[i-1] + dp[i-2];
            }
            else if(s[i] != ‘0‘ && s[i-1] == ‘0‘)
                dp[i] = dp[i-1];
        }

        return dp[len-1];
    }
};

总结

需要考虑很多的边界条件。

原文地址:https://www.cnblogs.com/shayue/p/10294475.html

时间: 2024-10-31 01:37:13

91. 解码方法的相关文章

leetcode 91. 解码方法 JAVA

题目: 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只包含数字的非空字符串,请计算解码方法的总数. 示例 1: 输入: "12" 输出: 2 解释: 它可以解码为 "AB"(1 2)或者 "L"(12). 示例 2: 输入: "226" 输出: 3 解释: 它可以解码为 "BZ" (2 26), "

力扣91.解码方法

题目 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只包含数字的非空字符串,请计算解码方法的总数. 示例 1: 输入: "12" 输出: 2 解释: 它可以解码为 "AB"(1 2)或者 "L"(12). 示例 2: 输入: "226" 输出: 3 解释: 它可以解码为 "BZ" (2 26), "V

91.解码方法(动态规划)

一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1'B' -> 2...'Z' -> 26给定一个只包含数字的非空字符串,请计算解码方法的总数. 初思路: 一看到本题,我就想用回溯算法来递归,因为遇到 10<s[:2]<27的时候 就可以递归两条路径,一条是分开,一条是合并 但是递归方法时间复杂度高,存在大量的重复计算,比如 分开转化s[0],s[1] 与合并s[0:2],还是回到处理 s[2:]的路径上,所以我再去看看答案. 观后思路: 本题确实就是 爬

leetcode——91.解码方法

class Solution: def numDecodings(self, s: str) -> int: a={} if int(s[0])==0: return 0 else: a[0]=1 if len(s)==1: return a[0] if int(s[0])>2 and int(s[1])==0: a[1]=0 if len(s)>1: return 0 if (int(s[0]+s[1])>26) or (int(s[0])<3 and int(s[1])=

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" "1010

[Swift]LeetCode639. 解码方法 2 | Decode Ways II

A message containing letters from A-Z is being encoded to numbers using the following mapping way: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 Beyond that, now the encoded string can also contain the character '*', which can be treated as one of the numbers

使用多字节字符集的跨平台(PC、Android、IOS、WP)编码/解码方法

随着移动端的发展,跨平台已成为通讯架构设计的重要考虑因素,PC.Android.IOS.WP等跨多平台间的数据通讯,必然要解决字符编码/解码的问题. 多字节字符集MBCS不是跨平台的首选字符集,面向跨平台.国际化的推荐字符集肯定是UNICODE. 写VC的人都知道,在以前VC++6.0中默认的字符集是多字节字符集,而VS2005及以后默认的字符集是Unicode,VS2013中默认不再对多字节字符串进行支持. 但对很多较早的服务端项目,依然使用的是多字节字符集,不过使用多字节字符集依然可以实现跨

LeetCode OJ:Decode Ways(解码方法)

A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 Given an encoded message containing digits, determine the total number of ways to decode it. For example,Given encoded

javascript——URI的编解码方法

有效的URI(统一资源标示符)是不能包含某些字符的,如空格,所以需要进行编码,编码方法有:encodeURI()和encodeURIComponent(), 对编的码进行解码方法有:decodeURI()和decodeURIComponent(). encodeURI()编的码只能decodeURI()解 encodeURIComponent()编的码只能decodeURIComponent()解, encodeURI():用于编码完整的URI,它不对URI中的特殊字符进行编码:例如冒号.前斜杠