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

把数字翻译成字符串

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

把数组翻译成字符串

题目:把数字翻译成字符串
描述:有一种将字母编码成数字的方式:'a'->1, 'b->2', ... , 'z->26'。现在给一串数字,返回有多少种可能的译码结果。注意到该题目中并未出现数字0对应的字母,当给定的数字串中出现0时,要根据其位置进行处理,因此这是本题的一个难点。

示例1:输入:"12",返回值:2
说明:输出结果表示存在2种可能的译码结果(”ab” 或”l”)
示例2:输入:"31717126241541717",返回值:192
说明:输出结果表示存在192种可能的译码结果

方法一:动态规划

在手动翻译一串数字时,我们会对数字串的第一个数字寻找对应的字母,接着加入数字串的第二个数字,并且寻找其对应的字母,当然为了得到更多的译码结果我们会对第一个数字和第二个数字组成的数寻找对应的字母,不过此时这个数必须小于等于26,否则没有对应的字母,接着我们在前面的翻译结果下,加入数字串的第三个数字以及第四个数字,以此类推,直到完成所有的数字串。记录之前翻译的结果而对当前翻译有影响的过程即为典型的动态规划过程,因此方法一我们介绍动态规划。上面的分析使我们成功的将问题转换为动态规划的问题,对于一个动态规划问题,我们只需要从两个方面考虑,那就是找出问题之间的联系,以及记录答案。用一句话解释动态规划就是记住之前的结果。解决动态规划通常分为四个步骤:
  • 问题拆解,找到问题之间的联系,即当前问题受到前面问题的影响
  • 状态定义
  • 转移方程推导
  • 具体实现

思路分析+实例

设置$dp[i]$为数字串从左到右第i个数字结尾的当前数字串所拥有的翻译方法数,往前一步,如果拼接成的数在[11,19]或者[21,26]的范围内 ,那么$dp[i] = dp[i-1] + dp[i-2] $;否则$dp[i] = dp[i-1]$;特别的当拼接的数为10或者20时,由于不存在数字0的译码,往前一步不会增加译码数,只有10或者20各自对应的译码,因此$dp[i]=dp[i-2]$最终的译码方法数为$dp[len-1]$,其中$len$表示数字串的长度。将上述分析可归纳为最终的转移方程,如下:
  • 如果$i=0$,$dp[i]=1$
  • 否则如下:
    --如果$nums[i]=0$,如果10或者20出现在开头,则$dp[1]=1$;否则$dp[i]=dp[i-2]$
    --否则如果拼接的数在规定的范围内,$dp[i]=dp[i-1]+dp[i-2]$
    --以上情况均不符合$dp[i]=dp[i-1]$

实例:任意给定数字串:”11227“

11227 当前译码方法数 译码方案 转移方程
1 $dp[0]=1$ 1a
11 $dp[1]=2$
11aa
11k
$i==1$,拼接的数11在范围内,因此$dp[1] =2$
112 $dp[2]=dp[1]+dp[0]=3$
112a
112aab
112kb
$dp[i] = dp[i-1]+dp[i-2]$
1122 $dp[3]=dp[2]+dp[1]=5$
1122aav
1122kv
1122alb
1122aabb
1122kbb
$dp[i] = dp[i-1]+dp[i-2]$
11227 $dp[4]=dp[3]=5$
11227aavg
11227kvg
11227albg
1227aabbg
11227kbbg
$dp[i]=dp[i-1]$

C++核心代码

class Solution {
public:
    /**
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */
    int solve(string nums) {
        // write code here
        int len=nums.size();
        if(len==0 || nums[0]=='0')//排除掉空数字串以及以0开始的数字串
            return 0;
        vector<int> dp(len,0);//dp[i]用于存储到第i位数字的译码方案数,其中i=0,1,2...len-1
        dp[0]=1;//i=0,第一位数结尾的译码方法数必为1
        for(int i=1;i<len;i++)
        {
            if(nums[i] == '0')
            {
                if(nums[i-1] =='1'||nums[i-1] == '2')
                {
                    if(i == 1) dp[i] = 1;//数字串以10或者20开头的情况
                    else dp[i] = dp[i-2];//数字串中存在10或者20的情况下,当前译码数等于后退两步的译码数
                }
            }
            else if(nums[i - 1] == '1' || (nums[i - 1] == '2' && nums[i] >= '1' && nums[i] <= '6'))
            {
                if(i == 1) dp[i] = 2;//数字串开始不是10或者20的情况,dp[1]=2
                else dp[i] = dp[i-1] + dp[i-2];
            }
            else
            {
                dp[i] = dp[i-1];
            }
        }
        
        return dp[len-1];
    }
}; 

复杂度分析

  • 时间复杂度:  单层遍历,因此时间复杂度为$O(n)$
  • 空间复杂度:使用了一个辅助数组$dp[len]$,因此空间复杂度为$O(n)$

方法二:递归

本题也可采用自上而下,从最大的问题开始,逐渐向下求解 ,因此方法二使用递归的方法。

图解+思路分析

任意给定数字串:”11221

递归,遍历数字的位,当前位翻译一种方法,如果当前位和下一位能结合成另一种翻译,则又可记录为一种方法。即存在每次只翻译一位数字和每次翻译两位数字的情况,将两者相加进行递归,当字符为0的时候,0没对应的解码,所以直接返回0 (此路解码废掉),如果当前字符等于1 或者 当前字符加上下一个字符合起来小于等于26 则可以一次解码两个字符。递归结束的条件为找到找到数字串的最后一位。在图中自上问下,从大的问题出发,每次将当前位作为一种翻译方法,如果当前位和下一位能结合则形成另一种翻译方法,以此递归。

JAVA核心代码

import java.util.*;

public class Solution {
    public int solve (String nums) {
        return back(nums.toCharArray(), 0);
    }
    // 递归函数
    public int back(char[] nums, int start){
        //当start走到终点时,证明已经翻译完毕,直接返回1
        if(start == nums.length){
            return 1;
        }    
        //当字符为0的时候,0没对应的翻译,所以直接返回0 (此路翻译废掉)
        if(nums[start] == '0')
            return 0;
        //每次翻译一个字符
        int res1 = back(nums,start+1);
        int res2 = 0;

        //如果当前字符等于1 或者 当前字符加上下一个字符合起来小于等于26 则可以一次翻译两个字符
        if((start < nums.length-1) && (nums[start] == '1' || (nums[start] == '2' &&nums[start+1] <= '6'))){
            res2 = back(nums,start+2);
        }
        //返回结果
        return res1 + res2;
    }
}

复杂度分析

  • 时间复杂度:递归的时间复杂度为递归的总次数*每次递归的数量,与动态规划的方法比较,有很多子问题被多次计算,因此时间更复杂,时间复杂度为
  • 空间复杂度:空间复杂度为递归的深度*每次递归创建变量的个数,因此空间复杂度为$O(n)$
全部评论
动态规划解法不对,只有6组用例通过
点赞 回复 分享
发布于 2022-04-06 16:00
这状态转移方程要怎么想到,自己画图找规律吗
点赞 回复 分享
发布于 2021-08-31 15:51

相关推荐

评论
13
1
分享

创作者周榜

更多
正在热议
更多
# 长得好看会提高面试通过率吗? #
4018次浏览 46人参与
# 离家近房租贵VS离家远但房租低,怎么选 #
16907次浏览 137人参与
# 米连集团26产品管培生项目 #
7309次浏览 226人参与
# 春招至今,你的战绩如何? #
15816次浏览 145人参与
# 你的实习产出是真实的还是包装的? #
3098次浏览 53人参与
# 沪漂/北漂你觉得哪个更苦? #
1553次浏览 41人参与
# MiniMax求职进展汇总 #
25164次浏览 322人参与
# HR最不可信的一句话是__ #
1091次浏览 32人参与
# AI面会问哪些问题? #
946次浏览 23人参与
# 你做过最难的笔试是哪家公司 #
1247次浏览 22人参与
# AI时代,哪个岗位还有“活路” #
2853次浏览 51人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152905次浏览 889人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
8021次浏览 43人参与
# XX请雇我工作 #
51155次浏览 171人参与
# 简历第一个项目做什么 #
32148次浏览 361人参与
# 简历中的项目经历要怎么写? #
311051次浏览 4265人参与
# 投格力的你,拿到offer了吗? #
178339次浏览 891人参与
# 你最满意的offer薪资是哪家公司? #
76981次浏览 375人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187605次浏览 1123人参与
# AI时代,哪些岗位最容易被淘汰 #
64760次浏览 890人参与
# 如果重来一次你还会读研吗 #
230018次浏览 2011人参与
# 正在春招的你,也参与了去年秋招吗? #
364353次浏览 2642人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务