第一次实习面试-fabonaci数列

来源:互联网 发布:淘宝里范冰冰的公益 编辑:程序博客网 时间:2024/05/20 01:36

       毕业前去卓越亚马逊参加暑期实习的面试,本来是3点开始,结果我2点半就到了,进去之后发现这种企业的写字楼是真NB,不论是从硬件设置还是公司气氛,一看就是NB公司。随后面试开始,一面是算法+数据结构,二面是设计模式+面向对象设计。至于这其中的具体细节我就不说了,网上的面经很多。

       说起这个数列,学过数学的人都知道,就是f(n)=f(n-1)+f(n-2),其中f(1)=f(0)=1;一般要输出f(k),使用递归就可以实现,递推的式子已经很明显,但是问题就怕深究,如果仅仅是满足于此,结果只能被面试官完虐。后来在网上找资料,才发现至少有5种方式来实现。具体参见http://www.cnblogs.com/CCBB/archive/2009/04/25/1443441.html

     1.最直观的思路和写法---递归

      int fibonacci(int n)

      {

            if(n==0 || n==1)

                  return 1;

            else

                 return fibonacci(n-1)+fibonacci(n-2);

       }

       这个程序因为在计算f(n)的时候,需要得到从f(2)到f(n-1),而计算f(n-1)时又重复计算了f(n-2),效率比较低,时间复杂度是o(n^2) 

     2.另一种递归

     这是在大_智_慧的博客上看到的,不同于以往的递归写法

     long fib(int n,long a,long b,int count)

     {

               if(count==n)

                        return b;

              return fib(n,b,a+b,++count);

    }

    int main()

   {

        fib(n,0,1,1);

   }

   这种方法其实是迭代方法的一种递归表现形式,显然a和b的初始值是0和1,而后b作为a的新值,而a+b作为b的新值,同时count加1,直到最底层,参考博客只是说这种方法可以得到近似线性的复杂度。

3.迭代法

long fib(int n)

{

     if(n<0)

         return -1;

     int a=1;b=1;

    for(int i=1;i<n;i++)

   {

           b=a+b;

           a=b-a;

    }

   return b;

}

这个程序显然实现了在o(n)的复杂度情况下输出f(n)(话说面试的时候我没有想出来,以前还见过这个程序,现在看是真TMD简单,估计面试官相当鄙视我)

4.通项公式

听上去有点高中数学的味道,但是不失为一种方法,而且理论上还是巨NB,为什么这么说?

使用考研时用的什么二阶差分方程解法(具体我已经忘了,好像是特征方程吧),解得它的解为

x1=(1+sqrt(5))/2,x2=(1-sqrt(5))/2,这样就得到:f(n)=(x1^n-x2^n)/sqrt(5)

时间复杂度为o(1),但是这仅仅是在理论上,因为会涉及到在计算方根时精度的损失问题,再就是开方和乘法的效率对执行时间的影响。

代码如下:

long fib(int n)

{

      double m=sqrt(5);

      doubie x=(1+m)/2;

      double y=(1-m)/2;

     return (pow(x,n)-pow(y,n))/m;

}

5.使用矩阵相乘

从通项公式可得到矩阵形式为:

f(n)                    1 1         f(n-1)

f(n-1)        =       1  0    *   f(n-2)

依次展开,直到f(1)=f(0)=1

f(n)                    1   1

f(n-1)   =            1   0   ^  (n-1)

这样,问题就转化为求一个二阶01矩阵的n-1次方(百度空间不太给力,表示形式欠佳),使用二分的方法实现,比如次方数是13,映射为2进制即1101.则矩阵A的13次=A^8*A^4*A1;

以下代码转自开头提到的博客,写的非常好:

class Matrix

{

public:

       long matr[2][2];

 

       Matrix(const Matrix&rhs);

       Matrix(long a, long b, long c, long d);

       Matrix& operator=(const Matrix&);

       friend Matrix operator*(const Matrix& lhs, const Matrix& rhs)

       {

              Matrix ret(0,0,0,0);

              ret.matr[0][0] = lhs.matr[0][0]*rhs.matr[0][0] + lhs.matr[0][1]*rhs.matr[1][0];

              ret.matr[0][1] = lhs.matr[0][0]*rhs.matr[0][1] + lhs.matr[0][1]*rhs.matr[1][1];

              ret.matr[1][0] = lhs.matr[1][0]*rhs.matr[0][0] + lhs.matr[1][1]*rhs.matr[1][0];

              ret.matr[1][1] = lhs.matr[1][0]*rhs.matr[0][1] + lhs.matr[1][1]*rhs.matr[1][1];

              return ret;

       }

};

 

Matrix::Matrix(long a, long b, long c, long d)

{

       this->matr[0][0] = a;

       this->matr[0][1] = b;

       this->matr[1][0] = c;

       this->matr[1][1] = d;

}

 

Matrix::Matrix(const Matrix &rhs)

{

       this->matr[0][0] = rhs.matr[0][0];

       this->matr[0][1] = rhs.matr[0][1];

       this->matr[1][0] = rhs.matr[1][0];

       this->matr[1][1] = rhs.matr[1][1];

}

 

Matrix& Matrix::operator =(const Matrix &rhs)

{

       this->matr[0][0] = rhs.matr[0][0];

       this->matr[0][1] = rhs.matr[0][1];

       this->matr[1][0] = rhs.matr[1][0];

       this->matr[1][1] = rhs.matr[1][1];

       return *this;

}

 

Matrix power(const Matrix& m, int n)

{

       if (n == 1)

              return m;

       if (n%2 == 0)

              return power(m*m, n/2);

       else

              return power(m*m, n/2) * m;

}

 

long fib4 (int n)

{

       Matrix matrix0(1, 1, 1, 0);

       matrix0 = power(matrix0, n-1);

       return matrix0.matr[0][0];

}

上面的是C++代码,做到了很好的功能封装,如果用C的话可以考虑使用结构来定义这个矩阵,数据成员是矩阵的4个元素即可。