首页 > 代码库 > 台阶问题引出的递归和非递归的思考

台阶问题引出的递归和非递归的思考

一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。


如果看到过这个题目的童鞋们,可能很快就有思路了,这个属于动态规划的典型题目。

基本思路如下:

假设n个台阶共有f(n)个跳法。那么我第一步可以跳1级,可以跳2级。

如果第一步跳1级,那么之后我有f(n-1)种跳法。

如果第一步跳2级,那么之后我有f(n-2)中跳法。

所以,得到下面的公式


一看到这个公式,很多人就会想到Finbonacci队列(兔子繁殖问题),很多人都是通过这个例子学会的递归方法。

代码如下:

<span style="font-size:18px;"><em>#include <iostream>
#include <time.h>


using namespace std;


int step(int n)
{
    if (n == 1)
        return 1;
    if (n == 2)
        return 2;
    return step(n-1) + step(n-2); 
}




int main()
{
   int n;
   int result;
   cin>>n;
   time_t start = clock();
   result = step(n);
   
   cout<<result<<endl;
   time_t end = clock();
   cout<<double(end - start)/CLOCKS_PER_SEC<<endl;
   return 0;


}</em></span>


代码中有几个问题:

1 int 类型太小,可能很多时候会越界

2 没有进行参数检测。


但是运行的时候,发现n数字比较小的时候,还可以,但是如果输入30,就需要100秒了,输入100,可能需要几个小时(我没有等这个时间)

所以递归算法的时间,是几何形的增长。我感觉是的复杂度,对于复杂度不会求,后面有机会再补充。


于是就想把递归变成非递归。

计算机上面很多时候就是时间和空间的一个换算。非递归,就是从f(1)开始一步一步的推到f(n)

于是,我们得到f(0) = f(1)=1 那么  

f(2) = f(0)+f(1)=2;

f(3)= f(1)+f(2) =3;

f(4) = f(2) +f(3) = 5;

可以看到f(n)需要记录两个变量f(n-1)和f(n-2)的数值,所以我们用变量a0 ,a1 分别表示,用循环替代递归

那么a2 = a0+a1;

a0 = a1;

a1 = a2;

注意上面的赋值顺序,先赋值a0,在赋值a1.

代码如下

<span style="font-size:18px;"><em>#include <iostream>
#include <time.h>

using namespace std;

int main()
{
   int n;
   int result;
   int a0 = 1;
   int a1 = 1;
   int a2 = 1;
   cin>>n;
   time_t start = clock();
   for (int i = 2; i <= n ; i++)
   {
       a2 = a0 + a1;
       //cout<<"a2 "<<a2<<endl;
       a0 = a1;
       a1 = a2;
    }   
   
   result = a2;
   cout<<result<<endl;
   time_t end = clock();
   cout<<double(end - start)/CLOCKS_PER_SEC<<endl;
   return 0;


}</em></span>


你在运行,输入大的数如50 100 也基本是瞬间完成的,他的效率应该是n级别。


所以,在理解程序上,递归简单一点,但是在效率上非递归要远远高于递归。所以需要根据自己的实际情况选择,最好都将递归改成非递归的方式。