剑指offer46:把数字翻译成字符串

这个题看了好几天,都没有思路,后来看到别人的题解,算是理解了一丢丢,现在整理下总体的思想。

题目

给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成"a",1翻译成"b",…,25翻译成"z"。一个数字可能有多个翻译。例如,12258有5种不同的翻译,分别是"bccfi"、“bwfi”、“bczi”、“mcfi"和"mzi”。请编写实现一个函数,用来计算一个数字有多少种不同的翻译方法。

举个例子

1的翻译个数是1

12的翻译个数是2

  • 1和2单独看作一个字母,即bc
  • 1和2看成一个整体,翻译成一个字母,即m

122的翻译个数3

  • 1、2、2单独看作一个字母,即bcc
  • 12 看作一个字母,2看作一个字母,即mc
  • 1 看作一个字母,22看作一个字母,即bw

重点来了,那么1221翻译的个数呢?共有以下两种情况!
情况一:12前2位当作一个整体,然后在其翻译方法后面添加1个21对应的字母,此时122112翻译的个数是一致的。

情况二:122前3位当作一个整体,然后在其翻译方法后面添加1个1对应的字母,此时1221122翻译的个数是一致的。

也就是说,如果我们知道了前i-2位和前i-1位的翻译个数,就能得到前i位的翻译个数

可以总结出如下的公式:
前i位可以翻译的个数 = 前i-1位可以翻译的个数+前i-2位可以翻译的个数

但是,这个公式还是存在一个bug,那就是如果第i为与第i-1位不能构成一个字母时,比如说1226或者1209,此时上述(1)过程就不能成立。所以,最终的公式内容为:

前 i 位 翻 译 的 个 数 = { 前 i − 1 位 可 以 翻 译 的 个 数 + 前 i − 2 位 可 以 翻 译 的 个 数 第 i 位 与 第 i − 1 位 构 成 数 字 小 于 26 且 大 于 9 前 i − 1 位 可 以 翻 译 的 个 数 第 i 位 与 第 i − 1 位 构 成 数 字 大 于 25 前i位翻译的个数={ \begin{cases} 前i-1位可以翻译的个数+前i-2位可以翻译的个数 &第i位与第i-1位构成数字小于26且大于9\\ 前i-1位可以翻译的个数 & 第i位与第i-1位构成数字大于25 \end{cases}} i={i1+i2i1ii1269ii125

如果用dp[]数组保存前i位翻译的个数,那么公式如下:
d p [ i ] = { d p [ i − 1 ] + d p [ i − 2 ] 第 i 位 与 第 i − 1 位 构 成 数 字 小 于 26 且 大 于 9 d p [ i − 1 ] 第 i 位 与 第 i − 1 位 构 成 数 字 大 于 25 dp[i]={ \begin{cases} dp[i-1] + dp[i-2] & 第i位与第i-1位构成数字小于26且大于9\\ dp[i-1] & 第i位与第i-1位构成数字大于25 \end{cases}} dp[i]={dp[i1]+dp[i2]dp[i1]ii1269ii125
122为例子,检测一下这个公式,
d p [ 3 ] = d p [ 2 ] + d p [ 1 ] = 2 + 1 = 3 dp[3] = dp[2] + dp[1] = 2 + 1 = 3 dp[3]=dp[2]+dp[1]=2+1=3
d p [ 2 ] = d p [ 1 ] + d p [ 0 ] = 1 + 1 = 2 dp[2] = dp[1] + dp[0] = 1 + 1 = 2 dp[2]=dp[1]+dp[0]=1+1=2




注释,若符合每一位的翻译个数时,需要将dp[0]dp[1]初始化为1。同时,如果如果第i-1位与第i位构成的数字是09、08等,以0开头的,需要将其列为第二种情况!
有了以上的公式,那么代码就很简单了。

代码演示(Java)

    public int translateNum2(int num) {
        char[] numArrays = String.valueOf(num).toCharArray();
        int length = numArrays.length;
        int[] dp = new int[length + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= length; i++) {
            int a = (numArrays[i-2] - '0') * 10 + (numArrays[i-1] - '0'); 
            //需要排除以0开头的两位数,如201
            if (a > 9 && a < 26) {
                dp[i] = dp[i-2] + dp[i-1];
            } else {
                dp[i] = dp[i-1];
            }
        }
        return dp[length];
    }

这道题用到了动态规划的思想!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值