题解 | #把数字翻译成字符串#

把数字翻译成字符串

http://www.nowcoder.com/practice/046a55e6cd274cffb88fc32dba695668

题目主要信息:
  • 字母到数字分别为1-26映射,没有0
  • 输入的数字是字符串,故非常大,超过了long long的表示范围
  • 但凡出现11-19,21-26的就可能出现两种译码结果
  • 求总后的译码结果种类
举一反三:

学习完本题的思路你可以解决如下题目:

BM62.斐波那契数列

BM63.跳台阶

BM64.最小花费爬楼梯

方法:动态规划(推荐使用)

知识点:动态规划

动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果

思路:

对于普通数组1-9,译码方式只有一种,但是对于11-19,21-26,译码方式有可选择的两种方案,因此我们使用动态规划将两种方案累计。

具体做法:

  • step 1:用辅助数组dp表示前i个数的译码方法有多少种。
  • step 2:对于一个数,我们可以直接译码它,也可以将其与前面的1或者2组合起来译码:如果直接译码,则dp[i]=dp[i1]dp[i]=dp[i-1];如果组合译码,则dp[i]=dp[i2]dp[i]=dp[i-2]
  • step 3:对于只有一种译码方式的,选上种dp[i1]dp[i-1]即可,对于满足两种译码方式(10,20不能)则是dp[i1]+dp[i2]dp[i-1]+dp[i-2]
  • step 4:依次相加,最后的dp[length]dp[length]即为所求答案。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    public int solve (String nums) {
        //排除0
        if(nums.equals("0"))  
            return 0;
        //排除只有一种可能的10 和 20
        if(nums == "10" || nums == "20")  
            return 1;
        //当0的前面不是1或2时,无法译码,0种
        for(int i = 1; i < nums.length(); i++){  
            if(nums.charAt(i) == '0')
                if(nums.charAt(i - 1) != '1' && nums.charAt(i - 1) != '2')
                    return 0;
        }
        int[] dp = new int[nums.length() + 1];
        //辅助数组初始化为1
        Arrays.fill(dp, 1);  
        for(int i = 2; i <= nums.length(); i++){
            //在11-19,21-26之间的情况
            if((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) != '0') || (nums.charAt(i - 2) == '2' && nums.charAt(i - 1) > '0' && nums.charAt(i - 1) < '7'))
               dp[i] = dp[i - 1] + dp[i - 2];
            else
                dp[i] = dp[i - 1];
        }
        return dp[nums.length()];
    }
}

C++实现代码:

class Solution {
public:
    int solve(string nums) {
        //排除0
        if(nums == "0")  
            return 0;
        //排除只有一种可能的10 和 20
        if(nums == "10" || nums == "20")  
            return 1;
        //当0的前面不是1或2时,无法译码,0种
        for(int i = 1; i < nums.length(); i++){  
            if(nums[i] == '0')
                if(nums[i - 1] != '1' && nums[i - 1] != '2')
                    return 0;
        }
        //辅助数组初始化为1
        vector<int> dp(nums.length() + 1, 1);  
        for(int i = 2; i <= nums.length(); i++){
            //在11-19,21-26之间的情况
            if((nums[i - 2] == '1' && nums[i - 1] != '0') || (nums[i - 2] == '2' && nums[i - 1] > '0' && nums[i - 1] < '7'))
               dp[i] = dp[i - 1] + dp[i - 2];
            else
                dp[i] = dp[i - 1];
        }
        return dp[nums.length()];
    }
};

Python代码实现:

class Solution:
    def solve(self , nums: str) -> int:
        #排除0
        if nums == "0":  
            return 0
        #排除只有一种可能的10 和 20
        if nums == "10" or nums == "20":   
            return 1
        #当0的前面不是1或2时,无法译码,0种
        for i in range(1, len(nums)): 
            if nums[i] == '0':
                if nums[i - 1] != '1' and nums[i - 1] != '2':
                    return 0
        #辅助数组初始化为1
        dp = [1 for i in range(len(nums) + 1)]  
        for i in range(2, len(nums) + 1):
            #在11-19,21-26之间的情况
            if (nums[i - 2] == '1' and nums[i - 1] != '0') or (nums[i - 2] == '2' and nums[i - 1] > '0' and nums[i - 1] < '7'):
                dp[i] = dp[i - 1] + dp[i - 2]
            else:
                dp[i] = dp[i - 1]
        return dp[len(nums)]

复杂度分析:

  • 时间复杂度:O(n)O(n),两次遍历都是单层
  • 空间复杂度:O(n)O(n),辅助数组dp
全部评论
你好,有个问题想问一下,如果字符串以0开头,答案就有问题了
2 回复 分享
发布于 2022-06-09 10:25
答案有问题吧,当nums[i-1] = 0; nums[i-2] 等于1或者2时,应该是dp[i] = dp[i-2],少了一个分支啊
12 回复 分享
发布于 2022-04-28 17:39
这个解法就是有问题,少考虑了dp[i] = dp[i-2]这一分支,比如"120",实际只有一种种类,按你这个程序就是2种
8 回复 分享
发布于 2022-08-17 15:30 江苏
120为啥会有两种解法呢
1 回复 分享
发布于 2023-09-03 21:33 江苏
这个官方题解问题挺多
点赞 回复 分享
发布于 2022-07-15 21:51
果然是有问题。
点赞 回复 分享
发布于 2022-09-14 22:26 广东
这题和原来的leetcode原题比起来,将0-25表示a-z改成了1-26,引发了很多问题。 另外我十分不理解的是,为什么每次dp数组都要比原来的数组长一个单位。谁来解释一下,这样在写for循环的时候,每次都要-1,很别扭。
点赞 回复 分享
发布于 2022-10-13 13:16 江苏
这题解法错了,将上面动图演示的“231211045”代入后得到的是10,而图中演示的是16。答案都不一致,代码肯定错了
点赞 回复 分享
发布于 2023-05-12 15:28 江西
将“231211045”代入代码运行后是10,服了
点赞 回复 分享
发布于 2023-05-12 15:29 江西
我想知道为什么初始状态dp[0] = 1,没有字符的情况也算一个译码情况吗?
点赞 回复 分享
发布于 2023-07-30 21:28 广东
官方也能出错,不严谨啊
点赞 回复 分享
发布于 2023-09-29 10:37 上海
动图上的结果有问题!!
点赞 回复 分享
发布于 04-03 20:20 北京
这题出得真拉,时间都耗在判断0上了
点赞 回复 分享
发布于 07-28 00:11 四川
题目都没看懂。。。。
点赞 回复 分享
发布于 10-16 15:48 湖南

相关推荐

11-15 18:39
已编辑
西安交通大学 Java
全村最靓的仔仔:卧槽,佬啥bg呢,本也是西交么
点赞 评论 收藏
分享
29 11 评论
分享
牛客网
牛客企业服务