《剑指offer》41、把数字翻译成字符串

《剑指offer》41题要求将数字转换为特定规则的字符串,例如12258有5种不同的翻译。本文探讨了使用递归和动态规划两种方法解决此问题。递归策略通过将原问题分解为子问题来求解,而动态规划则自下而上,从基础情况出发,通过迭代得到最终答案。动态规划中,定义状态为以第i位结尾的前缀串的翻译方案数,并通过转移方程计算得出总方案数。
摘要由CSDN通过智能技术生成

offer41的题目是给定一个数字,然后按照如下规则把它翻译为字符串:
0翻译成”a”,1翻译成”b”,……,11翻译成”l”,……,25翻译成”z”。
这样一来,一个数字可能有多个翻译——例如12258有5种不同的翻译,它们分别是”bccfi”、”bwfi”、”bczi”、”mcfi”和”mzi”。
现在给出一个数字,要求其总的翻译方法数。

递归

本来这题我是想和“最长不含重复字符的字符串”,以及“第一个只出现一次的字符”放在一起讲的,但是后来发现是完全不一样的问题。“把数字翻译成字符串”的核心在于将原问题转为两个子问题。
比如12258,可以视为1+2258或12+558这两个问题;这样一来就可以发现,问题的本质是递归。

# offer41-solution 1
def getTranslationCount(self, s):
    """
    :type s: str
    :rtype: int
    """
    if not s: return 0
    if len(s) == 1: return 1
    
    # 判断字符是否为‘0’,避免0X的形式
    if s[0] != '0' and int(s[:2]) >= 0 and int(s[:2]) <= 25:
        return self.getTranslationCount(s[2:]) + self.getTranslationCount(s[1:])
        return self.getTranslationCount(s[1:])

动态规划

其实本问题能想到DP的话,想必也是极好的。动态规划是自下而上解决问题,从已知的 base case 出发,存储前面的状态,迭代出最后的结果。
先定义状态:以第 i 位结尾的前缀串翻译的方案数。
转移方程:
假设翻译字符串的第 i i i位:可以单独作为一位来翻译
如果第 i − 1 i−1 i1位和第 i i i位组成的数字在 10 到 25 之间,可以把这两位连起来翻译。
f ( i ) f(i) f(i)表示以第 i i i位结尾的前缀串翻译的方案数,然后考虑第 i i i位单独翻译和与前一位连接起来再翻译对 f ( i ) f(i) f(i)的贡献——单独翻译对 f ( i ) f(i) f(i)的贡献为 f ( i − 1 ) f(i - 1) f(i1);如果第 i − 1 i−1 i1位存在且 i − 1 i−1 i1位和 i i i位形成的数字 x x x满足 10 ≤ x ≤ 25 10≤x≤25 10x25,那么两个字符连起来一起翻译对 f ( i ) f(i) f(i)的贡献为 f ( i − 2 ) f(i - 2) f(i2)。其余的情况为 0。

# offer41-solution 2
class Solution:
    def getTranslationCount(self, number):
        """
        :type number: int
        :rtype: int
        """
        if number < 0:
            return 0
        numberStr = str(number)

        return self.getTranslateCount(numberStr)

    def getTranslateCount(self, numberStr):  # 从数组尾部出发,动态规划
        length = len(numberStr)
        counts = [0] * length
        # count=0
        for i in range(length - 1, -1, -1):
            count = 0
            if i < length - 1:
                count += counts[i + 1] # 与前面的总计数相加
            else:
                count = 1

            if i < length - 1:
                digit1 = int(numberStr[i])
                digit2 = int(numberStr[i + 1])
                converted = digit1 * 10 + digit2
                if converted >= 10 and converted <= 25:
                    if i < length - 2:  # 分两种不同情况
                        count += counts[i + 2]
                    else:
                        count += 1
            counts[i] = count
        return counts[0]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值