• 斐波拉契数列 【微软面试100题 第十九题】


    题目要求:

      写一个函数,输入n,求斐波拉契数列的第n项。斐波拉契数列的定义如下:

      

      参考资料:剑指offer第9题、编程之美2.9

    题目分析:

      方法1:递归法,效率很低,而且会计算很多重复;

      方法2:迭代法,通过保存中间项避免重复计算,时间复杂度O(n);

      方法3:公式法,时间复杂度O(1),因为公式中引入了无理数,所以不能保证结果的精度;

      方法4:分治策略,可以用矩阵来表示,则,(这个式子是通过计算A、A2、A3、、、观察出来的)其中,则上面这个式子可以表示为:

    则F2 = Y2_11 = A(11表示矩阵的第1行1列元素).

         现在剩下的问题就是求An了,可以把n用二进制表示:n = ak*2^k + ak-1*2^k-1 + ... + a1*2 + a0,其中ai = 0 或1 ,i = 0,1,2... k。例如:n = 5 = b’101 = 1*22 + 0*21+1*20。这样

    则,我们知道An最多经过log2n乘法就能够得到,而不用A*A*A这样计算n次。

    代码实现:

      方法1代码:

    #include <stdio.h>
    
    #define uint64 unsigned __int64 
    
    uint64 Fibonacci(int n);
    
    int main(void)
    {
        int n;
    
        while(1)
        {
            printf("请输入n值:");
            scanf("%d",&n);
    
            printf("n = %d,Fibonacci(n) = %I64u
    ",n,Fibonacci(n));    
        }    
        return 0;
    }
    uint64 Fibonacci(int n)
    {
        if(n <= 0)
            return 0;
        else if(n == 1)
            return 1;
        else
            return (Fibonacci(n-1)+Fibonacci(n-2));
    }
    View Code

      方法2代码: 

    #include <stdio.h>
    #include <assert.h>
    
    int main(void)
    {
        int n,i = 0;
        int x,y;
    
        while(1)
        {
            printf("请输入n值:");
            scanf("%d",&n);
            assert((n >= 0) && (n <= 92));//用这种方法的n最大为92,否则就溢出了。
    
            i = 0;
            x = 0;
            y = 1;
            while(i < n)
            {
                y = x+y;
                x = y-x;
                i++;
            }
            if(n <= 0)
                y = x;
            printf("n = %d,Fibonacci(n) = %d
    ",n,y);
    
        }    
        return 0;
    }
    View Code

      方法3代码:

    #include <stdio.h>
    #include <assert.h>
    #include <math.h>
    
    double Pow(double x,unsigned int n);
    
    int main(void)
    {
        int n;
        int fibo;
        double a,b,c;
        a = sqrt(5.0);
        b = (1+a)/2;
        c = (1-a)/2;
        while(1)
        {
            printf("请输入n值:");
            scanf("%d",&n);
            assert((n >= 0));
            
            int x = pow(b,n);
            int y = pow(c,n);
            fibo = (int)(a*(Pow(b,n)-Pow(c,n))/5);
            printf("n = %d,fibonacci(n) = %d
    ",n,fibo);
        }    
        return 0;
    }
    double Pow(double x,unsigned int n)
    {
        double result = 1;
        while(n)
        {
            if(n & 0x01)
                result *= x;
            x  = x*x;
            n >>= 1;
        }
        return result;
    }
    View Code

      方法4代码: 

    #include <stdio.h>
    #include <assert.h>
    
    const int MAXLENGTH = 10;
    
    struct Matrix 
    {
        unsigned side;
        __int64 dat[MAXLENGTH*MAXLENGTH];//也可以用行/列来表示(row、line),会更方便一点。
    };
    
    // 方阵的乘法 
    void MatrixMult(const Matrix a, const Matrix b, Matrix &m)
    {
        unsigned int i,j,k;
        assert(a.side == b.side);
        m.side = a.side;
        for (i=0; i < m.side; ++i)
            for (j=0; j < m.side; ++j)
            {
                m.dat[i*m.side+j] = 0;
                for (k=0; k<m.side; ++k)
                    m.dat[i*m.side+j] += a.dat[i*a.side+k]*b.dat[k*b.side+j];
            }
    }
    
    __int64 Fibonaci(unsigned n)
    {
        if (n==0) 
            return 0;
    
        --n;    // 计算矩阵prod的n-1次幂
    
        Matrix res;    
        res.side = 2;
        res.dat[0] = 1; res.dat[1] = 0; 
        res.dat[2] = 0; res.dat[3] = 1;
    
        Matrix prod;        
        prod.side = 2;
        prod.dat[0] = 1;  prod.dat[1] = 1;
        prod.dat[2] = 1;  prod.dat[3] = 0;
    
        // 只需要O(logn)的复杂度就能算出x的n次幂  
        while (n)
        {
            // 如果n的最低二进制位为1,则乘上对应的幂次prod
            if (n&1) MatrixMult(res, prod, res);
            MatrixMult(prod, prod, prod);
            n >>= 1;
        }
        return res.dat[0];
    }
    
    int main(void)
    {
        int i;
    
        for(i = 0;i < 20;i++)
        {
            printf("%I64u
    ",Fibonaci(i));
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    Redis面试题 总结
    C++ 自由存储区是否等价于堆?(转)
    线程同步方式
    epoll的原理 (一)(转)
    C/C++ 中 volatile 关键字详解(转)
    Linux堆内存管理
    找出数组中出现次数超过一半的数
    剑指offer-复杂链表的复制
    已知二叉树前序中序遍历重建二叉树
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/tractorman/p/4058305.html
Copyright © 2020-2023  润新知