原题链接:
https://leetcode-cn.com/problems/three-steps-problem-lcci/
题目描述
三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。
示例1:
输入:n = 3
输出:4
说明: 有四种走法
示例2:
输入:n = 5
输出:13
提示:
- n范围在[1, 1000000]之间
动态规划思想
1.确定状态(两个核心:1最后一步 2化成子问题)
2转移方程
3开始和边界条件
4计算顺序
思路:
还剩最后一步时,有三种情况,走1个台阶,走2个台阶,走3个台阶(n>=3);
由此得出转移方程:f(n)=f(n-1)+f(n-2)+f(n-3),(n>=3)
n=1:只能走一阶,共一种方法;
n=2:可以走两个一阶或者一个两阶,共两种方法;
n=3:可以走三个一阶或者先一个一阶后一个两阶或者先一个两阶后一个一阶或者一个三阶,共四种方法。
C语言代码(超时):
int waysToStep(int n){
long long sum=0;
if(n==1) return 1;
else if(n==2) return 2;
else if(n==3) return 4;
else return (waysToStep(n-1)+waysToStep(n-2)+waysToStep(n-3))%1000000007;
}
超时分析:
采用了自顶向下的思路递归,从最大的原问题f(n)开始向下逐渐分解规模,直到f(1)和f(2)底层,然后逐层返回答案,每一项都要重复计算,耗时较大;
AC代码:
int waysToStep(int n){
long long a[1000000],i;
if (n < 4) {
return n == 3 ? 4 : n;
}
a[1]=1;
a[2]=2;
a[3]=4;
for(i=4;i<=n;i++){
a[i]=(a[i-1]+a[i-2]+a[i-3])%1000000007;
}
return a[i-1];
}
采用数组存取每一步计算出来的结果,内存消耗大。
对空间进一步优化代码:
int waysToStep(int n){
long long sum,a,b,c,i;
if (n < 4) {
return n == 3 ? 4 : n;
}
a=1;
b=2;
c=4;
for(i=4;i<=n;i++){
sum=(a+b+c)%1000000007;
a=b;
b=c;
c=sum;
}
return sum;
}
定义少量的变量循环使用,消耗内存小。
思路:
后两种方法均采用自底向上的动态规划思想,从规模最小的f(1)和f(2)开始往上推,直到得出我们想要的f(n),每一次迭代都包含前面子问题中计算出来的结果,无重复计算!