LeetCode刷题——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

思路

这个题有点像爬楼梯,但是比爬楼梯复杂很多。有很多限制条件,甚至题目没给出来,比如不能以0开头,不能连续出现两个0。 总之分解之后的数值只能在[1,26]之间。

先用递归的思想,自顶向下的思考问题。这里的“顶”是指字符串最后一个字符。

如果连续两个数字符合条件([1,26],如果像09这种,就不是两个数字符合条件,因为拆分成两个的话,会出现0和9, 0不符合条件。简单的方式是看这两个字符形成的数字是不是在[10,26]之间。其中10在这之前被考虑过。),

则有两种解法,一种是分成两个数字,还有一种是整个解成一个数字。

考虑限制条件比较麻烦,以下有先后顺序:

  1. 不能以0开头
  2. 不能出现连续两个0
  3. 如果当前数字不是0,则可以先将两个数字拆开解(解法1)
  4. 如果连续两个数字符合条件,则将两个数字一起解(解法2)
  5. 其他大于26的情况,只能拆开解,已经在第3步考虑过了

代码

递归

class Solution(object):
    def num(self,s, i):
        # 不能以0开头
        if int(s[0]) == 0:
            return 0

        if i <= 0:  # <是有必要的
            return 1

        # 不能出现两个0
        if i >= 1 and int(s[i] + s[i - 1]) == 0:
            return 0

        res = 0

        # 当前数字不是0
        if int(s[i]) != 0:
            # 先拆分一步
            res = self.num(s, i - 1)

        digit = int(s[i - 1] + s[i])

        # 如果连续的两位数符合条件,有两种解法
        if 10 <= digit <= 26:
            res += self.num(s, i - 2)

        return res


    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        return self.num(s, len(s) - 1)

在这里插入图片描述

记忆化搜索

记忆化搜索也很简单,将计算结果保存起来即可。

dp = {0: 1}


class Solution(object):

    def num(self, s, i):
        if i not in dp:
            if i <= 0:  # <是有必要的
                dp[i] = 1
                return 1

            # 不能出现两个0
            if i >= 1 and int(s[i] + s[i - 1]) == 0:
                dp[i] = 0
                return 0

            res = 0

            # 当前数字不是0
            if int(s[i]) != 0:
                # 则可以拆分连续的两个
                res = self.num(s, i - 1)

            digit = int(s[i - 1] + s[i])

            # 如果连续的两位数符合条件
            if 10 <= digit <= 26:
                # 可以把连续的两个作为一起
                res += self.num(s, i - 2)
            dp[i] = res
        return dp[i]


    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 不能以0开头
        if int(s[0]) == 0:
            return 0

        return self.num(s, len(s) - 1)

在这里插入图片描述
但是不知道为啥,网站说跑不过测试用例"10",说我输出为2,我手动将测试用例改成"10"输出明明是1:

在这里插入图片描述
纠结了一会,不管它。改成动态规划看能过不。

动态规划

采用动态规划自底向上的解决问题,也就是从字符串第一个字符开始考虑。

class Solution:
    def numDecodings(self, s: str) -> int:
        n = len(s)
        if s[0] == '0':
            return 0
        
        dp = [1] + [0] * n

        # 用i+1替换为i,不然容易数组越界
        # i 从[0,n-1]
        for i in range(0,n):
            # 不能出现两个0
            if i >= 1 and int(s[i] + s[i - 1]) == 0:
                return 0
            
            # 当前数字不是0
            if int(s[i]) != 0:
                dp[i+1] = dp[i] # 解法1

            if i >= 1 and 10 <= int(s[i - 1] + s[i]) <= 26:
                dp[i+1] += dp[i-1] # 解法2
        
        return dp[n]

这里要注意一点的是,本来如果有两个解法是写成dp[i] = dp[i-1]+dp[i-2],但是容易数组越界,要考虑的情况很多,不信可以试下。

因此这里令i = i + 1,问题就好处理了,但是处理s时还是一样的。

在这里插入图片描述
被我刷到了28ms ^v^

原创文章 176 获赞 286 访问量 18万+

猜你喜欢

转载自blog.csdn.net/yjw123456/article/details/106011805