01.问题描述
三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。n范围在[1, 1000000]之间。
函数调用:int waysToStep(int n)
02.问题分析
首先我们可以看到这道题的数据很大,这个对编程者也是很大的一个挑战。一般这种题会要求对结果取模。除开很大的数据,我们很多人看到的第一个想法应该是递归吧。只要想着初始条件:
n = 1, return 1;
n = 2, return 2;
n = 3, return 4;
那么递归的条件我们就能很容易找到。
(1)递归方法
这种方法的时间复杂度是真的很大很大,呈指数增长。我在我电脑上运行个60就十多秒都运行不出来。所以,对于这种大数据的,第一种递归方法枪毙。
int waysToStep(int n){
if(n<=2)
return n;
if(n == 3)
return n+1;
else
return (waysToStep(n-1)+waysToStep(n-2)+waysToStep(n-3))%1000000007;
}
(2)递归的优化
这种方法就是减少一些递归中,重复调用的情况。毕竟如果递归60,60就会递归到59、58、57,下一个递归就是58、57、56,这样子就会出现重复计算,造成时间浪费。但是只要把计算出来的数,贴上标签,再第二次递归的时候,就直接调用那个数组里的存在的计算出来的数,就会减少一些重复计算的时间啦。用这个可以通过计算,不过处理这种大数据的问题,还是要要注意栈溢出的问题,这里把数据弄成long long 就可以了。
long long checker(long long* flag, int n)
{
if (n <= 2)
return n;
if(n == 3)
return n+1;
if (flag[n])//存在
return flag[n];
flag[n] = (checker(flag,n-1) + checker(flag,n-2) +checker(flag,n-3))%1000000007;//不存在则计算
return flag[n];
}
int waysToStep(int n){
if (n <= 2)
return n;
if(n == 3)
return n+1;
long long *flag = (long long*)calloc((n + 1),sizeof(long long));//动态初始化一个数组
return checker(flag, n);
}
就是时间太长了。。。
(3)动态规划
dp[i]的含义就是走i个台阶的最多的方法。因为只有三种爬楼梯方法,所以只能从dp[i-1],dp[i-2],dp[i-3]爬上去。初始化的条件我们上面已经列出来了。如果对动态规划不怎么明白的,可以看一下我上一篇博客。戳这里前往所以这个动态规划的迭代是:
dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
int waysToStep(int n){
long long dp[10000000];
int i,j;
dp[0] = 1;
dp[1] = 2;
dp[2] = 4;
if(n<=3)
return dp[n-1];
for(i=3;i<=n;i++)
{
dp[i] = dp[i-1]+dp[i-2]+dp[i-3];
if(dp[i] > 1000000007)
dp[i] = dp[i]%1000000007;
}
return dp[n-1];
}
看起来很标准的动态规划了,但是某个大佬吐槽我的的空间复杂度还是太大了,不是最优的解,然后就出现了第四种方法,究极节约时间空间的方法。
(4)究极优化的动态规划
其实看出来,定义这么大一个数组,空间复杂度为O(n),其实里面重复就在调用三个数,因为有三种方法嘛。我们直接用三个数代替他,然后挨着递加一下,岂不是很香香??qwq出现了,究极简化怪:
int waysToStep(int n){
long long a=1,b=2,c=4,sum;
int i;
if(n<=2)
return n;
if(n == 3)
return n+1;
for(i=3;i<n;i++)
{
sum = (a+b+c)%1000000007;
a = b;
b = c;
c = sum;
}
return sum;
}
究极香香!!完美。
代码的优化方法总结:
1.总的来说,就是先暴力递归,想到暴力解决的办法,尝试做出来。
2.再通过优化,减少时间复杂度,达到能通过的样子。
3.能够用动态规划的,可以尽量使用,最近觉得动态规划做题很香香。
4.优化以后,能够最终优化掉空间复杂度,把代码使用达到真正的简洁,那就是大佬,真正会使用动态规划了。
qwq希望这篇博客能帮到您,本篇博客由一位大佬指导代码完成,如发现类似博客极可能是那位大佬,请狠狠地点个赞,谢谢咩~