现在的位置: 首页 > 综合 > 正文

【求职面试】斐波那契数列(C#版)

2011年05月22日 ⁄ 综合 ⁄ 共 1692字 ⁄ 字号 评论关闭

经典就是经典,不论多少年,经典永远不会改变。

语言,框架总有一天会过时,但是唯独经典永远存在。这就是研究这些经典算法的永恒。

当我这样一个.net程序员去应聘Java, C++, Android岗位时,我发现框架语言特性,都被抛弃。就这样海绵一挤,我的4年水分就出来了。剩下的精华已不多。而能贯穿各个岗位的,就是这些虽在身边,但却忽视如空气般的,底层知识和应用能力。

你的经验,有多少水分呢?在一个公司久了,出来晒晒,你就发现,其实你会的并不多。

 

有趣问题:

1,有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?

答:这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有一种登法;登上三级台阶,有两种登法;登上四级台阶,有三种方法……所以,1, 1,2,3,5,8,13……登上十级,有89种。

2,数列中相邻两项的前项比后项的极限是多少,就是问,当n趋于无穷大时,F(n)/F(n+1)的极限是多少?

答:这个可由它的通项公式直接得到,极限是(-1+√5)/2,这个就是所谓的黄金分割点,也是代表大自然的和谐的一个数字。

 

数学表示:

Fibonacci数列的数学表达式就是:

F(n) = F(n-1) + F(n-2)

F(1) = 1

                                  F(2) = 1

 

公式是给出来了,可是为什么是这个公式呢?你有没有想过?

公式是怎么提炼出来的?我数学不好,所以我的经验就是从找规律开始:

  如果起点是0的话,对于第一级台阶来讲有F(1)=1种走法,对于第二级来讲有F(2)=1种走法。对于第三极台阶,有1+2, 2+1两种走法。对于第四级台阶,可以从第三极台阶+1,也可以从第二级台阶+2,也就是F(4) = F(3) + F(2),以此类推。

 写代码也很简单:

        ///<summary>
/// Fibonacci递归算法。时间复杂度O(n)=O((3/2)^n),指数级算法
///</summary>
public ulong FibonacciRecursion(int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n must > 0.");

if (n == 1 || n == 2)
return 1;
return FibonacciRecursion(n - 1) + FibonacciRecursion(n - 2);
}

那么这个超级简单的递推程序,效率是多少呢?让我们加个数组,记录每次递归的次数,同时可以output一下,看看这些有趣的数字。

        ///<summary>
/// 递归输出Fibonacci
///</summary>
public ulong FibonacciRecursionCount(int n, int[] countArray)
{
countArray[n]++; //count the compute number.

if (n < 0)
throw new ArgumentOutOfRangeException("n must > 0.");

if (n == 1 || n == 2)
return 1;
return FibonacciRecursionCount(n - 1, countArray) + FibonacciRecursionCount(n - 2, countArray);
}

这时,可以得到每个fib(i)被计算的次数:

fib(10) = 1     fib(9) = 1      fib(8) = 2      fib(7) = 3

fib(6) = 5      fib(5) = 8      fib(4) = 13    fib(3) = 21

fib(2) = 34   fib(1) = 55    fib(0) = 34

可见,计算次数呈反向的Fibonacci数列,这显然造成了大量重复计算。

我们令T(N)为函数fib(n)的运行时间,当N>=2的时候我们分析可知:

T(N) = T(N-1) + T(N-2) + 2

而fib(n) = fib(n-1) + fib(n-2),所以有T(N) >= fib(n),归纳法证明可得:

fib(N) < (5/3)^N

N>4时,fibN>= (3/2)^N

标准写法:

抱歉!评论已关闭.