一条包含字母 A-Z 的消息通过以下映射进行了编码:
‘A‘ -> 1
‘B‘ -> 2
...
‘Z‘ -> 26
要解码已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:
"AAJF",将消息分组为 (1 1 10 6)
"KJF",将消息分组为 (11 10 6)
注意,消息不能分组为(1 11 06),因为"06"不能映射为"F",这是由于"6"和"06"在映射中并不等价。
给你一个只含数字的非空字符串 s ,请计算并返回解码方法的总数。
题目数据保证答案肯定是一个32位的整数。
输入:s = "226"
输出:3
解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6)。
输入:s = "06"
输出:0
解释:"06" 不能映射到 "F" ,因为字符串含有前导 0("6" 和 "06" 在映射中并不等价)。
对于给定的字符串 s,设它的长度为 n,其中的字符从左到右依次为 s[1], s[2], ... , s[n]
。我们可以使用动态规划的方法计算出字符串 s 的解码方法数。
具体地,设 \(dp[i]\) 表示字符串 \(s\) 地前 \(i\) 个字符 \(s[1,...,i]\) 的解码方法数。在进行状态转移时,我们可以考虑最后一次解码使用了 \(s\) 中的哪些字符,那么会有下面两种情况:
将上面的两种状态转移方程在对应的条件满足时进行累加,即可得到\(dp[i]\)的值。在动态规划完成后,最终答案即为\(dp[n]\)。
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
dp = [1] + [0]*n
for i in range(1, n+1):
# 逐位判断,如果当前位置不为‘0’,则当前位置为dp表中的值1
if s[i-1] != ‘0‘:
dp[i] += dp[i-1]
# 如果前面一位不为‘0’,则前面一位可以和当前位置的数字组合 然后判断是否<26
if i>1 and s[i-2] != ‘0‘ and int(s[i-2:i]) <= 26:
dp[i] += dp[i-2]
return dp[n]
注意到在状态转移方程中,\(dp[i]\) 的值仅与 \(dp[i-1]\) 和 \(dp[i-2]\) 有关,因此我们可以使用三个变量进行状态转移,省去数组的空间。
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
# a = dp[i-2], b = dp[i-1], c = dp[i]
a, b, c = 0, 1, 0
for i in range(1, n + 1):
c = 0
if s[i - 1] != ‘0‘:
c += b
if i > 1 and s[i - 2] != ‘0‘ and int(s[i-2:i]) <= 26:
c += a
a, b = b, c
return c
原文:https://www.cnblogs.com/kanka/p/14690807.html