来审一下题,num最大的范围在int内。这个数字emmm,反正不大记得,总之位数也不多好像。
额,那么我们如何分析这道题呢,以下是分析的过程:
就对题目中的12258来分析,如果给你这道题,你会怎么做?
如果是我,我会先拿出1变成b,后面2258再另作分析,当然,由于a-z是对应的0-25,所以我们还能先把12()拿出来,然后258再另作分析。啊哈,这样,dp的转移方程就有了不是么,应该长下面这样:
c当且仅当当前的第i位与第i-1位形成的数字大于等于10且小于等于25时取1,否则取0,emmm,是不是说清楚了?
那我们可以开始写代码了,当然,这种是可以用滚动数组节省空间复杂度的,可以看看《剑指offer》42连续子数组的最大和:剑指offer42:连续子数组的最大和_lsgoose的博客-CSDN博客来看看用数组和用几个变量的区别,然后,这里写上用滚动数组的代码:
class Solution {
public:
int translateNum(int num) {
string src=to_string(num);
auto len=src.size();
//p记录f(i-1)
//q记录f(i-2)
//这里r初始化为1 表示第一个数字单独拿出来的情况
int p,q=0,r=1;
for(int i=0;i<len;++i)
{
p=q;
q=r;
r=0;
r+=q;
if(i==0)
{
continue;
}
auto pre=src.substr(i-1,2);
if(pre<="25"&&pre>="10")
{
r+=p;
}
}
return r;
}
};
结果如下所示:
当然,有自底向上的,也会有自顶向下的递归写法:
class Solution {
public:
int translateNum(int num) {
if(num<10)
{
return 1;
}
if(num%100>=10&&num%100<=25)
{
return translateNum(num/10)+translateNum(num/100);
}
return translateNum(num/10);
}
};
这里的细节:
用除法代替i-1和i-2操作,用%100完成对末尾两位数的提取
结果如下所示:
为什么递归的内存消耗还小一些,有无懂哥解释以下......
总结一下:dp的题目关键在于判断是否是dp,或者说是要能自顶向下找出规律写出转移方程,然后还能自底向上或者自顶向下写出代码,有时候用滚动数组可以优化空间复杂度。