leetcode91.解码方法

1.题目描述

一条包含字母 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) 。

2.解题思路

1.递归

2.递归2

3.动态规划

建立一维 dp 数组,其中 dp[i] 表示s中前i个字符组成的子串的解码方法的个数,长度比输入数组长多多1,并将 dp[0] 初始化为1。现在来找状态转移方程,dp[i] 的值跟之前的状态有着千丝万缕的联系,就拿题目中的例子2来分析吧,当 i=1 时,对应s中的字符是 s[0]='2',只有一种拆分方法,就是2,注意 s[0] 一定不能为0,这样的话无法拆分。当 i=2 时,对应s中的字符是 s[1]='2',由于 s[1] 不为0,那么其可以被单独拆分出来,就可以在之前 dp[i-1] 的每种情况下都加上一个单独的2,这样 dp[i] 至少可以有跟 dp[i-1] 一样多的拆分情况,接下来还要看其能否跟前一个数字拼起来,若拼起来的两位数小于等于26,并且大于等于 10(因为两位数的高位不能是0),那么就可以在之前 dp[i-2] 的每种情况下都加上这个二位数,所以最终 dp[i] = dp[i-1] + dp[i-2],是不是发现跟斐波那契数列的性质吻合了。所以0是个很特殊的存在,若当前位置是0,则一定无法单独拆分出来,即不能加上 dp[i-1],就只能看否跟前一个数字组成大于等于 10 且小于等于 26 的数,能的话可以加上 dp[i-2],否则就只能保持为0了。具体的操作步骤是,在遍历的过程中,对每个数字首先判断其是否为0,若是则将 dp[i] 赋为0,若不是,赋上 dp[i-1] 的值,然后看数组前一位是否存在,如果存在且满足前一位是1,或者和当前位一起组成的两位数不大于 26,则当前 dp[i] 值加上 dp[i - 2]。最终返回 dp 数组的最后一个值即可

3.代码实现

1.会超时

class Solution(object):
    def __init__(self):
        self.res = 0
    def isRightNum(self,num):
        if num != str(int(num)):
            return False
        num = int(num)
        if num>=1 and num<=26:
            return True
        else:
            return False
    def dfs(self,s,begin):
        if begin > len(s):
            return
        elif begin == len(s):
            self.res += 1
            return
        for i in range(1,3):
            if self.isRightNum(s[begin:begin+i]):
                self.dfs(s,begin+i)
            
            
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        if s[0]=="0":
            return 0
        self.dfs(s,0)
        return self.res

2.也会超时。。。

class Solution(object):
    def __init__(self):
        self.res = 0
    def isRightNum(self,num):
        if num != str(int(num)):
            return False
        num = int(num)
        if num>=1 and num<=26:
            return True
        else:
            return False
    def dfs(self,s,begin):
        
        if begin == len(s):
            return 1
        elif s[begin] == "0":
            return 0
        ans1 = self.dfs(s,begin+1)
        ans2 = 0
        if begin+2<=len(s):
            if self.isRightNum(s[begin:begin+2]):
                ans2 = self.dfs(s,begin+2)
        return ans1 + ans2
            
            
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        return self.dfs(s,0)

3.动态规划,通过

class Solution(object):
    def isRightNum(self,i,j):
        # 首位不可以为0
        if i == 0:
            return 0
        num=i*10+j
        if num>=1 and num<=26:
            return 1
        else:
            return 0
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        if s[0]=="0":
            return 0
        length=len(s)
        f=[0]*(length+1)
        f[0]=1
        f[1]=1
        for i in range(1,length+1):
            if s[i-1]=="0":
                f[i] = 0
            else:
                f[i] = f[i-1]
            if i>1:
                f[i] += f[i-2]*self.isRightNum(int(s[i-2]),int(s[i-1]))
        return f[length]
            
        
        

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值