題目
一條包含字母 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在這之前被考慮過。),
則有兩種解法,一種是分成兩個數字,還有一種是整個解成一個數字。
考慮限制條件比較麻煩,以下有先後順序:
- 不能以0開頭
- 不能出現連續兩個0
- 如果當前數字不是0,則可以先將兩個數字拆開解(解法1)
- 如果連續兩個數字符合條件,則將兩個數字一起解(解法2)
- 其他大於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^