数据结构与算法之[把数字翻译成字符串]&&动态规划

简介: 数据结构与算法之[把数字翻译成字符串]&&动态规划

前言:最近在刷动态规划的算法题目,感觉这一类题目还是有一点难度的,但是不放弃也还是能学好的,今天给大家分享的是牛客网中的编程题目[把数字翻译成字符串],这是一道经典的面试题目,快手,字节跳动等大厂出国这道题目。题目有点绕,需要进行分类讨论最好配合画图工具进行理解,这样能更好理解这道题目。


一.题目


28b02d6472a5a1f5dbf979bf7ad768d4.png

619808a6dc64103a387a206898673c98.png


二.进一步剖析题目


1.关于动态规划思想


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


2.分析题目


①分析题目:能够译码的数字不会大于26,即有效的译码范围为 [1,26]。

②确定状态:以数组 "12345" 为例,首先要明确两点:


  • 依题意可知,数组中所有的数字都必须参与译码,比如数组 "1234" 的某一种译码方式为 “1,2,3,4",那么当数组尾再添加一个元素 "5" 时,刚才的译码方式就会变为 "1,2,3,4,5",即 "1,2,3,4" 和 "1,2,3,4,5" 是同一种译码方式。


由于所有数字都要参与译码,所以只要译码方式中存在个位数 "0",那么就都是无效的。


当新加入一个数字"5" 时,其除了可以单独作为一个数字参与译码外,也可以与其左边的数字组成数字组合后再参与译码,即 "45" ,然后此时有多少种译码方式就取决于剩余的数字 即 "123" 了,这和前面所说的是同一个道理,只是此时把 "4"和"5" 看作是一个整体,可以理解为:原本数组 "123" 存在某种译码方式为 "1,2,3",现在加入 "45",译码方式就变成了 "1,2,3,45"。


由于有效的译码范围为 [1,26],所以新加入的数字 "5" 只需要考虑与其左边的数字组成两位数组合,无需再考虑组成更大的组合了,比如三位数 "345" 等等。


数字组合必须是十位数,比如 "0"和"2" 组成的 "02" 也是不符合译码要求的。


理解了上面两点后,现在我们从数组 "12345" 的子串"1"开始分析,然后逐步往后添加元素,设数组 x 有 f(x) 种有效的译码方式:


当数组为 "1" 时,有以下译码方式:


①1


f("1")=1


接着加入数字"2",数组为 "12" 时,有以下译码方式:


①1,2


②12


f("12")=2


其中第①种是从 数组 "1" 的译码方式 演变过来的,就是在其基础上再加上单个数字 "2"。


接着加入数字"3",数组为 "123" 时,有以下译码方式:


①1,2,3


②12,3


③1,23


f("123")=3


其中第①、②种是从 数组 "12" 的译码方式 演变过来的,就是在其基础上再加上单个数字 "3";


而第③种是从 数组 "1" 的译码方式 演变过来的,就是在其基础上再加上数字组合 "23"。


接着加入数字"4",数组为 "1234" 时,有以下译码方式:


①1,2,3,4

②12,3,4

③1,23,4

④1,2,34

⑤12,34

其中第①、②、③种是从 数组 "123" 的译码方式 演变过来的,就是在其基础上再加上单个数字 "4";


而第④、⑤种是从 数组 "12" 的译码方式 演变过来的,就是在其基础上再加上数字组合 "34";


由于 "45" 不在有效译码的范围内,所以这两种译码方式会被抛弃掉。


f("1234")=3


可见,数组 "1234" 的译码方式 是由 数组 "123"的译码方式 和 数组 "12"的译码方式 组成的。


根据上面的分析,当数组继续扩张到 "12345" 时,那么其译码方式就为:


当新加入的数字 "5" 单独作为个位数参与译码时,此时的译码方式 就等同于 数组 "1234" 的译码方式,这组译码方式是有效的,因为个位数 "5" 在有效的译码范围内;


而 "5" 与其前一位数字组成十位数 "45" 时,此时的译码方式 就等同于 数组 "123" 的译码方式,而这组译码是否有效则取决于 "45" 是否在有效的译码范围内。


即 f("12345") = f("12345" - "5") + f("12345" - "45") = f("1234") + f("123") = 3+3 = 6,但是由于 "45" 不在有效的译码范围内,所以 f("123") 的结果不能算在内,所以最终结果应该为3。


可见,枚举到某位数字时,此时有多少种译码方式,可以由之前的译码方式相加得出,即当前的状态可以利用之前的状态,这是典型的动态规划。


③状态转移方程:f(x)=f(x-1)+f(x-2)(其中 x 表示数组长度,f(x) 表示有多少种有效的译码方式;是否加上 f(x-1) 取决于 nums[x] 是否在 [1,9] 内,即 nums[x] 需要满足不为0;是否加上 f(x-2) 则取决于 nums[i-1] 与 nums[i] 的数字组合是否在 [10,26] 内)


时间复杂度:O(N) ,需要遍历一次数组

空间复杂度:O(N) ,需要声明一个状态数组记录f(x)


3.C++代码


class Solution {
  public:
    int solve(string nums) {
        // write code here
        if(nums[0]=='0')return 0;
        vector<int>dp(nums.size(),0);
        dp[0]=1;
        for(int i=1;i<dp.size();i++)
        {
            if(nums[i]!='0')
            {
                if(nums[i-1]=='1')
                {
                    dp[i]=dp[i-1]+(i-2>=0?dp[i-2]:1);
                    continue;
                }
                if(nums[i-1]=='2'&&(nums[i]-'0'>0&&nums[i]-'0'<7))
                {
                    dp[i]=dp[i-1]+(i-2>=0?dp[i-2]:1);
                    continue;
                }    
                dp[i]=dp[i-1];            
                }
                else {
                    if(nums[i-1]-'0'==1||nums[i-1]-'0'==2)
                    {
                        dp[i]=dp[i-1];
                        continue;
                    }
                    return 0;           
                }
            }
             return dp[nums.size()-1];
}
};


相关文章
|
18天前
|
存储 算法
深入了解动态规划算法
深入了解动态规划算法
44 1
|
18天前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
2月前
|
存储 缓存 NoSQL
redis数据结构-字符串
redis数据结构-字符串
34 1
|
2月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
9天前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
32 2
动态规划算法学习三:0-1背包问题
|
15天前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
41 1
两个字符串匹配出最长公共子序列算法
|
9天前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
37 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
9天前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
40 0
动态规划算法学习二:最长公共子序列
|
18天前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
|
9天前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
42 0