把数字翻译成字符串

196 阅读3分钟

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

问题描述

剑指 Offer 46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

示例:

输入:12258

输出:5

解释:12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"。

分析问题

对于一个数字的每一位 num[i] 来说,它有两种选择。

  • 它作为单独的一部分进行翻译。
  • 它和它前面的一位作为一个整体来进行翻译(要求其范围为10~25)。

假设给定的数 nums= x1x2x3x4...xi-2xi-1xi...xn,数x1x2x3x4...xi-2的方案数为f(x-2),数x1x2x3x4...xi-2xx-1的方案数是f(x-1)。

  • 当xi-1xi整体翻译时,x1x2x3x4...xi-2xi-1xi的整体方案是f(i-2)。
  • 当xi单独翻译时,x1x2x3x4...xi-2xi-1xi的整体方案是f(i-1)。

image-20211121213303802

所以可以得出:

f(i) = {f(i2)+f(i1),当数字xi1xi可以翻译时f(i1),当数字xi1xi不可以翻译时\begin{cases} f(i-2)+f(i-1) , 当数字xi-1xi可以翻译时 \\ f(i-1),当数字xi-1xi不可以翻译时 \end{cases}

有了递推关系,就可以使用动态规划来求解。我们用 dp[i] 代表以 xi 为结尾的数字的翻译方案数量。则根据递推关系我们可以求出状态转移方程为:

dp[i] = {dp[i2]+dp[i1],当数字xi1xi可以翻译时dp[i1],当数字xi1xi不可以翻译时\begin{cases} dp[i-2]+dp[i-1] , 当数字xi-1xi可以翻译时 \\ dp[i-1],当数字xi-1xi不可以翻译时 \end{cases}

其中要想xx-1xi可以被翻译,就需要其属于[10,25]。

下面我们来看一下边界条件,对于只有一位数字来说,它只能有1种翻译方案,故dp[1]=1,当有两位数字时,如果其属于[10,25],我们可以知道其有2种翻译方案,所以dp[2]=2,又因为dp[2]=dp[1]+dp[0],故dp[0]=1。

我们来看一个具体的例子,假设输入是12258。

image-20211121215247256

image-20211121215309972

因为dp[i]只依赖于dp[i-2]和dp[i-1],所以我们只需要申请两个变量就可以求解,从而省去dp的空间。

下面我们来看一下代码如何实现。

class Solution:
    def translateNum(self, num):
        #想将num转成字符串,方便获取xi-1xi
        s = str(num)
        a = b = 1
        for i in range(2, len(s) + 1):
            if "10" <= s[i - 2:i] <= "25":
                temp=a+b
            else:
                temp=a
            b = a
            a = temp
        return a

该算法的时间复杂度是O(n),空间复杂度也是O(n)。

优化

这道题我们也可以采用数学求余的方法来求解。具体来说。

我们可以利用求余运算 num % 10 和求整运算 num // 10 ,来获取数字num的每一位数字(获取顺序为个位、十位、百位…)。因此,可通过求余和求整运算实现从右向左的遍历计算,从而把算法的空间复杂度减低为O(1)。

class Solution:
    def translateNum(self, num):
        a = b = 1
        y = num % 10
        while num != 0:
            num //= 10
            x = num % 10
            tmp = 10 * x + y
            if 10 <= tmp <= 25:
                c = a + b
            else:
                c = a
            b=a
            a=c
            y = x
        return a

该算法的时间复杂度是O(n),空间复杂度是O(1)。