1. 程式人生 > >斐波那契數列(二)--矩陣優化演算法

斐波那契數列(二)--矩陣優化演算法

之前寫了一篇從斐波那契數列分析遞迴與動態規劃(JAVA)來優化斐波那契數列,這樣可以使演算法的時間複雜度從O(n^2)變到O(n),這是使用遞迴公式f(n)=f(n-1)+f(n-2)求斐波那契數列的最優演算法,但是這只是一維世界下的極限。下面我們將其從一維上升到二維,用二階矩陣推導斐波那契數列,該演算法的複雜度為O(logn)。

矩陣定義

一個m*n的矩陣是一個由m行n列元素排成的矩形陣列。矩陣裡的元素可以是數字符號或者數學式.

下面是一個典型的二階矩陣

                    

二階矩陣的乘法

         

高效冪運算


第一種方法在高效冪運算(JAVA)中有類似的描述,雖然本文中是對矩陣進行冪運算,實質是一樣的

第二種方法利用位運算轉換成二進位制處理

斐波那契數列的矩陣演算法

import java.util.Scanner;

/**
 *  [F(n+1) F(n)]    [1  1 ]^n
    |           |   =|     |
    [F(n) F(n-1)]    [1  0 ]
 * */
public class Main {
    // 公式矩陣  
    private static final int[][] UNIT = {{1, 1}, {1, 0}};
    // 零矩陣  
    private static final int[][] ZERO = {{0, 0}, {0, 0}};

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] m = fb(n);
        System.out.println(m[0][1]);
    }
    
    /**
     * 利用二進位制進行高效冪運算
     * 求斐波那契數列
     * */
    public static int[][] fb(int n) {
        if (n == 0) {
            return ZERO;
        }
        if (n == 1) {
            return UNIT;
        }
        if (n%2 == 0) {
            System.out.println(n >> 1);
            int[][] matrix = fb(n >> 1);

            return Multiply(matrix, matrix);
        } else {
            int[][] matrix = fb((n - 1) >> 1);
            return Multiply(Multiply(matrix, matrix), UNIT);
        }

    }
    
    /**
     * 矩陣乘法
     * */
    public static int[][] Multiply(int[][] m, int[][] n) {

        /**
         * 對於斐波那契數列來說,行和列都是2,這樣寫更易於理解,下面也給出了標準的矩陣乘法演算法,是通用的
         * 用到此演算法,除非進行演算法學習和研究,否則一般都是進行較大資料的斐波那契求值,所以對結果取(10e9)+7的模
         * */
        int[][] r = new int[2][2];
        r[0][0] = (m[0][0]*n[0][0] + m[0][1]*n[1][0])%1000000007;
        r[0][1] = (m[0][0]*n[0][1] + m[0][1]*n[1][1])%1000000007;
        r[1][0] = (m[1][0]*n[0][0] + m[1][1]*n[1][0])%1000000007;
        r[1][1] = (m[1][0]*n[0][1] + m[1][1]*n[1][1])%1000000007;
        return r;
    }
}

標準矩陣乘法演算法:

    public static int[][] Multiply(int[][] m, int[][] n) {
//        標準計算矩陣乘法演算法
        int rows = m.length;
        int cols = n[0].length;
        int[][] r = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                r[i][j] = 0;
                for (int k = 0; k < m[i].length; k++) {
                    r[i][j] += m[i][k] * n[k][j];
                }
            }
        }
        return r;
    }
}