算法与数据结构面试题(17)-求Fibonacci数的和

题目


题目:定义Fibonacci 数列如下:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+f(n-2) n=2
8
输入n,用最快的方法求该数列的第n 项。
要求时间复杂度为Olog(n)


解题思路


前人文章:http://zhedahht.blog.163.com/blog/static/25411174200722991933440/


问题转化为求下面的公式




这个2×2的矩阵用一个矩阵对象表示。里面有4个属性,分别表示f(n),f(n-1),f(n-1),f(n-2),求f(n)就是得到第一个属性的值。


求矩阵的公式,采用分治法。


算法与数据结构面试题(17)-求Fibonacci数的和_第1张图片


这样就得到了矩阵的{1,1,1,0}的n-1次方的值。


下面是2个矩阵相乘的公式:


算法与数据结构面试题(17)-求Fibonacci数的和_第2张图片


代码


public class Problem19 {
    // 2×2的矩阵
    class Matrix2X2 {
        // 第一排第一个位置
        int pos00;
        // 第一排第二个位置
        int pos01;
        // 第二排第一个位置
        int pos10;
        // 第二排第二个位置
        int pos11;

        public Matrix2X2() {

        }

        public Matrix2X2(int pos00, int pos01, int pos10, int pos11) {
            this.pos00 = pos00;
            this.pos01 = pos01;
            this.pos10 = pos10;
            this.pos11 = pos11;
        }
    }

    // 2个2×2的矩阵相乘得到新的矩阵
    class MatrixMultiply {
        public Matrix2X2 multiply(Matrix2X2 m1, Matrix2X2 m2) {
            return new Matrix2X2(m1.pos00 * m2.pos00 + m1.pos01 * m2.pos10,
                    m1.pos00 * m2.pos01 + m1.pos01 * m2.pos11, m1.pos10
                            * m2.pos00 + m1.pos11 * m2.pos10, m1.pos10
                            * m2.pos01 + m1.pos11 * m2.pos11);
        }
    }

    MatrixMultiply multiplyer = new MatrixMultiply();

    // 求Fibonacci数第N个数
    public Matrix2X2 getFibo(int n) {
        if (n < 0) {
            return null;
        }

        Matrix2X2 matrix22 = null;
        if (n == 1) {
            matrix22 = new Matrix2X2(1, 1, 1, 0);
        }
        // 偶数
        else if (n % 2 == 0) {
            matrix22 = getFibo(n / 2);
            matrix22 = multiplyer.multiply(matrix22, matrix22);
        }
        // 奇数
        else if (n % 2 != 0) {
            //提取出第一个矩阵,生下来的矩阵就是偶数个,但是要记住在最后要把提取的第一个矩阵算上。
            matrix22 = getFibo((n - 1) / 2);
            matrix22 = multiplyer.multiply(matrix22, matrix22);
            matrix22 = multiplyer.multiply(matrix22, new Matrix2X2(1, 1, 1, 0));
        }

        return matrix22;
    }
    //原始的递归法
    public static int getFibo2(int n){
        {
            if (n==0||n==1)
            {
                return n;
            }
            else
            {
                return getFibo2(n-1)+getFibo2(n-2);
            }
        }
    }
    
    public static void main(String[] args) {
        int n = 30;
        Matrix2X2 matrix = new Problem19().getFibo(n - 1);
        int fn = matrix.pos00;
        System.out.println(fn);
        int fn2 = Problem19.getFibo2(n);
        System.out.println(fn2);
    }

}


输出


832040
832040

扩展


有网友说可以通过下面的通项公式一步求解


Fibonacci通项公式:

an=1/√[(1+√5/2) n-(1-√5/2) n]


你可能感兴趣的:(数据结构,算法)