青蛙跳台阶,1次跳1步,1次还可以跳2步。问n个台阶几种跳法
递归的思路:
无论是斐波那契还是汉诺塔等递归问题,都具有相同的,已经走过的过程,下一次迭代只是上次的结果和这次需要迭代的,就可以运用递归
思路: | |
一个问题直接求解时不好求解,如果可以将其划分成其子问题,并且子问题和原问题有相同的解法时,就可以使用递归的方式解决 | |
递归的两个条件: | |
1. 将问题划分成其子问题,要求:子问题要与原问题具有相同的解法 | |
2. 递归的出口 |
假设有一个函数f(n)可以算出n个台阶青蛙有几种跳法
当n=1 1种
当n=2 2种
当n>2
可以把这种情况看成,第一步跳一步后面有f(n-1)个(+)第一步跳2步后面有f(n-2)个方法,然而后面的方法数可以递归出来。
这种青蛙跳台阶的问题本质上就是一种斐波那契的变形
按照跳台阶的思路我一开始认为跳到最后一个台阶 前面还是N-1个台阶,F(N-1) = ?就是几
这种不对,还少了一种情况,还需要加上最后2个台阶一步跳上去 ,那么就是F(N-1) + F(N-2)
我觉得和从第一个台阶看也是这样的,第一个台阶剩下N-1个,第一第二个台阶一步跳上去还剩N-2个,也是F(N-1) + F(N -2)
那么如此就得出了如下的关系式
假设有3个台阶
青蛙第一次有两种跳法,要么跳一个,要么跳2个
跳一个还剩2个台阶,而跳2个台阶的方法数已知
跳2个还剩1个,而跳1个台阶的方法数已知
则运用递归,完整代码如下:
#include <stdio.h>
int f(int n)
{
if ( n <= 0 )
{
printf("没台阶还算?\n");
return 0;
}else if(1 == n)
{
return 1;
}
else if (2 == n)
{
return 2;
}
else //这种情况是n>2的情况,因为前面把情况都写了,最后就直接else。
return f(n - 1) + f(n - 2);
}
int main()
{
int n = 0;
printf("请输入台阶数\n");
scanf("%d", &n);
int ret = 0;
ret = f(n);
printf("有%d种跳法\n", ret);
return 0;
}
但是这种递归有很多冗余,计算了许多相同的f(n),和斐波那契数列的递归一样,递归在有时候是有缺陷的。可以用迭代的方式避免。例如斐波那契的时间复杂度为O(2^N)。
循环方式实现
class Solution {
public:
int numWays(int n)
{
if(n == 0)
return 1;
if(n<=2)
{
return n;
}
int f1 = 1;
int f2 = 2;
int ret = 0;
for(int i = 3 ; i <= n; i++)
{
ret = (f1 + f2) % 1000000007;
f1 = f2;
f2 = ret;
}
return ret;
}
};