题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
解题思路1:
- 这种题目关键是想到递归思想;
- 第一次跳楼梯,先跳1阶,剩余n-1阶未跳,定义剩余跳跃方法为:f(n-1)
- 第一次跳楼梯,先跳2阶,剩余n-2阶未跳,剩余跳跃方法为:f(n-2)
- 以此循环,每次都这样循环,定义好边界和初始条件:f(1)=1; f(2)=2;
- 因为每一次跳跃可以跳1阶或2阶,所以得出递归公式为:f(n)=f(n-1)+f(n-2);
注意:
- 编写递归代码的关键是,只要遇到递归,就把它抽象成一个递推公式,不用想一层层调用关系,不要试图用人脑去分解递归的每个步骤!
- 递归代码,重复计算的次数太多了,而且还存在堆栈溢出问题;
- 通过上面公式可以通过定义两个变量a,b,num=a+b;a是下一次的b,总和num是下一次的a,这样如此循环,可以说省去不断调用函数,增加的栈开销。
class Solution {
public:
int numWays(int n)
{
if(n < 2) return 1;
int num;
int a=1, b=1;
for(int i=2; i<n+1; i++)
{
num=(a+b)%1000000007;
b=a;
a=num;
}
return num;
}
};
解题思路2:
递归代码转非递归,避免堆栈溢出。
public int climbStairs(int n) {
if(n <= 1)
return 1; //题目要求n=0,返回值也是1
if(n==2)
return 2;
int* tmp = new int[n+1];
//int[] tmp = new int[n+1]; //部分编译器支持这种写法
tmp[1] = 1;
tmp[2] = 2;
for(int i=3;i<=n;i++){
//n阶楼梯爬法拆解:第一步走了1阶+f(n-1) 第一步走了2阶+f(n-2)
tmp[i] = tmp[i-1]+tmp[i-2];
}
return tmp[n];
}
错误代码:
直接通过递归,不断调用函数,不断增加堆栈大小,最后超出时间限制;
系统栈或虚拟机栈空间一般不大,当递归规模比很大,调用层次很深,就会有栈溢出的风险。
class Solution {
public:
int numWays(int n)
{
if(n <= 1)
{
return 1;
}
//if(n==1) return 1;
if(n==2) return 2;
return ways(n);
}
int ways(int n)
{
if(n <= 1) return 1;
if(n==2) return 2;
return (ways(n-1) + ways(n-2))%1000000007;
}
};
参考链接:https://blog.csdn.net/ten_sory/article/details/64126341