A message containing letters from A-Z
is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.
26个英文字母分别代表一种映射关系,现给定一个非空字符串,用26个字母的映射关系对字符串进行解码,分析总共有多少种解码方式。
Example 1:
Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
这道题的分析的情况比较多,稍微有点复杂,利用动态规划来做:
创建dp数组,其长度与s的长度相同,dp[ i ] 代表以s[ i ]为结尾的字符串有多少种组成字符串的方法。初始化时,将dp全部初始化为0,代表s的所有位置都不能被解码。
一、分析边界情况,如果s是以‘0’开头,那么必定无法被解码,返回0;
二、如果s的长度为一,则无论如何都只有一种解码方式,直接返回1;
三、
A、s长度大于等于2的情况,首先初始化dp[ 0 ] = 1 ,由于在后续分析中会涉及到 i-1和 i-2 的情况,所以初始化时还需要考虑dp[ 1 ]的情况,我们来根据s[ i ]的值对dp[ 1 ]进行分析:s[ i ]在任何情况下只有 0~9 十种情况。首先如果 s[ 1 ] = '0' 时,‘0’必须和前一位进行组合才能得到一种解码方式,且其前一个数必须是‘1’或‘2’,否则无法解码;当 1<= int( s[ 1 ] ) < = 6时,s[ 1 ]既可以作为单独的一位字符与前面的字符串进行组合,这个时候dp[ 1 ] = 2,同时也可以与前一位的字符串进行组合,组合的时候必须保证前一位字符为‘1’或‘2’,这个时候dp[ 1 ] =1;剩下一情况就是 7 <= int(s[ 1 ]) <= 9 ,s[ 1 ]既可以作为单独的一位字符与前面字符串进行组合,这个时候dp[ 1 ] = 2,同时也可以与前一位字符串进行组合,组合的时候必须保证前一位字符为‘1’,这个时候dp[ 1 ] =1,以上就将dp[ 1 ]的情况分析清楚,直接初始化就行了;
B、下面我们考虑s字符串长度大于2的情况,由于s字符串索引从0开始,前面dp[ 0 ]和dp[ 1 ]已经分析完毕,所以for循环应该从2开始,代表从s的第三个字符开始。此时的分析与dp[ 1 ]的分析几乎相同,s[ i ]在任何情况下仍然只有 0~9 十种情况,当s[ i ] = ‘0’时,‘0’必须和前一位进行组合才能得到一种解码方式,且其前一个数必须是‘1’或‘2’,这个时候dp[ i ] = dp[ i-2 ],否则无法解码,返回0;当 1<= int( s[ 1 ] ) < = 6时,s[ i ]既可以作为单独的一位字符与前面的字符串进行组合,这时dp[ i ] = dp[ i-1 ],同时也可以与前一位的字符串进行组合,组合的时候必须保证前一位字符为‘1’或‘2’,这种情况下dp[ i ] = dp[ i-1 ] + dp[ i-2 ];当7 <= int(s[ 1 ]) <= 9 时,s[ i ]既可以作为单独的一位字符与前面字符串进行组合,即dp[ i ] =dp[ i-1 ],同时也可以与前一位字符串进行组合,组合的时候必须保证前一位字符为‘1’,这时dp[ i ] = dp[ i-1 ]+dp[ i-2 ] 。综上情况分析完毕,直接根据上述条件写出代码,返回dp最后一个元素即可。
总体方法可能稍显麻烦,但是理解上思路相对清晰些,本题思路与Reference的思路差不多,都是比较朴素的方法,如果解释没有看懂可以移步Reference。
Solutions:
Python
class Solution:
def numDecodings(self, s: str) -> int:
if s[0]=='0':
return 0
if len(s) == 1:
return 1
dp = [0 for i in range(len(s))]
dp[0] = 1
if s[1] == '0':
if s[0] == '1' or s[0] =='2':
dp[1] = 1
elif 1<= int(s[1]) <= 6:
if s[0] == '1' or s[0] =='2':
dp[1] =2
else:
dp[1] = 1
else:
if s[0] == '1':
dp[1] = 2
else:
dp[1] = 1
for i in range(2,len(s)):
if s[i] == '0':
if s[i-1] =='1' or s[i-1]=='2':
dp[i] = dp[i-2]
else:
return 0
elif (1 <= int(s[i])) and (int(s[i]) <= 6):
if (s[i-1] == '1' or s[i-1] == '2'):
dp[i] = dp[i-1]+dp[i-2]
else:
dp[i] = dp[i-1]
else:
if s[i-1] == '1':
dp[i] = dp[i-2] +dp[i-1]
else:
dp[i] = dp[i-1]
return dp[-1]
Reference: