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^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章