Fibonacci数列

    Fibonacci数列是一个应用很广泛的数列,它的形式如下:

        0,1,1,2,3,5,8,13,21,34…..

它的规则为:

                Fn-1 + Fn-2  (n > 1)

         

Fn =         1      (n==1)

              

                0     (n==0)

对于这个数列我们很容易就可以写出它的代码实现:

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

面对一个算法的时候,我们必须考虑以下三个问题:

1 它是正确的吗?

2 它将能耗费多少时间,其时间耗费关于n是一个什么样的函数?

3 我们能改进它吗?

 

显然第一个问题在这里是成立的,对于第二个问题 当n == 1时, T(1) = 1;当n == 0时,T(0) = 2;包括两次if判断.当 n >= 2时,

T(n) = T(n-1) + T(n-2) + 3; 这里的3包括两次if判断和一个加法运算.

经过分析便可以知道这个时间复杂度是极高的,随着n的增大成指数增长.好,第三个问题来了,我们可以改进它吗?

我们知道时间复杂度和空间复杂度在优化方便是一对不可兼得的死对头,为了在时间上予以优化,我们得牺牲空间来换取。我们再来分析一下前面的那个递归算法,我们可以看到,当我们每次计算一个n值时都需计算其前n-1个值,很多重复的运算确实浪费了我们很多时间,我们可以从此方面进行改进。我们在计算的时候只需保存前n个结果,在计算第n+1个结果的时候,就可以直接取值相加就可以了,而不用再进行重复的计算。好的,我们来看一下代码

int Fibonacci(int n) { int *a,i; if (n == 0) { return 0; } a = (int*)malloc(sizeof(int) * n); a[0] = 1; a[1] = 1; for (i=2; i < n; ++i) { a[i] = a[i-1] + a[i-2]; } return a[n-1]; }

好了,面对这个算法,让我们再问下自己上面的三个问题:

1 它是正确的吗?

2 它将能耗费多少时间,其时间耗费关于n是一个什么样的函数?

3 我们能改进它吗?

第一个肯定满足,我已经测试过啦,第二个,这个算法的时间复杂度是多少呢?T(0) = 1;T(1) = 3;  当n >= 2时.

T(n) = n + 3; 归结起来,时间复杂度应为O(n). 好,第三个问题来了,我们能改进它吗?ok, 我们再来分析一下上面一个算法,用了n个int型的空间来保存前面的数据,然后返回a[n-1],即返回第n个元素的值。好的,从这里我们开动一下自己的脑筋,我们可以明白,我们每次需要的仅仅是 Fibonacci(n-1) 和 Fibonacci(n-2) 其他的值我们是不需要的。所以我们无需用一个数组来保存前面的值,只需两个变量就OK了,好的,我们来看一下代码:

int Fibonacci(int n) { int val1,val2,ret,i; if (n == 0) { return 0; } if (n == 1) { return 1; } val1 = 0; val2 = 1; for (i=2; i <= n; ++i) { ret = val1 + val2; val1 = val2; val2 = ret; } return ret; }

看下代码,我们用两个变量来实现了。我们来把它和上一个比对一下,发现我们在时间复杂度上别没有进行改进,而是在空间复杂度上进行了改进。当然这也是一种进步,也是需要的。

好的,现在我们再来问自己哪三个问题:

1 它是正确的吗?

2 它将能耗费多少时间,其时间耗费关于n是一个什么样的函数?

3 我们能改进它吗?

回答: 1 正确 2 O(n)  3 我可以吗?你可以吗?

好的,如果你还可以对他进行改进的话,那我期待你的答案哦。

点赞