Fibonacci数列(利用矩阵快速幂)

本文介绍了一种利用矩阵快速幂方法高效计算斐波那契数列的方法,并进一步扩展到更复杂的递推公式。通过构造特定的矩阵A和矩阵B,实现了对数级时间内求解递推序列的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ....

现在要求输入一个整数n,请你输出斐波那契数列的第n项

可以看出 第1项为0, 第2项为1, 第三项为1, 第四项为2 = 第三项+第二项, ...... 第n项 = 第(n-1)项+第(n-2)项

即  f(n) = f(n-1) + f(n-2)

设 A为m×p 的矩阵,B为p×n 的矩阵,那么称 m×n 的矩阵 C为 矩阵 A 和 B 的乘积,记作C = AB

 

=> f(n) = C(0,0)

矩阵乘法满足结合律,即 

(AB)C = A(BC)(AB)C=A(BC)

那我们就需要求出 A^(n-1)

例如 4 = 100

4 = 1 * 2 ^(2) + 0 * 2 ^(1) + 0 * 2 ^(0)

A = A ^(1*2^(2)) * A  ^(0*2^(1)) * A  ^(0*2^(0))

代码:

public static class Matrix {
        int[][] value;
        int row, col;
        Matrix(int row, int col) {
            value = new int[row][col];
            this.row = row;
            this.col = col;
        }
        Matrix(int row, int col, int op) {
            value = new int[row][col];
            this.row = row;
            this.col = col;
            int minRowCol = row < col ? row : col;
            for (int i = 0; i < minRowCol; i++) {
                value[i][i] = op;
            }
        }
        Matrix(Matrix matrix) {
            value = new int[matrix.row][matrix.col];
            this.row = matrix.row;
            this.col = matrix.col;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    value[i][j] = matrix.value[i][j];
                }
            }
        }
        Matrix multiply(Matrix matrix) {
            Matrix ret = new Matrix(row, col);
            for(int i = 0; i < row; i++) {
            	for(int j = 0; j < matrix.col; j++) {
            		for(int k = 0; k < col; k++) {
            			ret.value[i][j] += value[i][k] * matrix.value[k][j];  
            		}
            	}
            }
            return ret;
        }
        Matrix power(int n) {
            Matrix ret = new Matrix(row, col, 1);
            Matrix matrix = new Matrix(this);
            while (n > 0) {
                if (n % 2 == 1) {
                    ret = ret.multiply(matrix);	// 	算 A
                }
                n = n / 2;
                matrix = matrix.multiply(matrix);	// 算 A(^n)
            }
            return ret;
        }
    }
    public static int fibonacci(int n) {
        int m = n - 1;
        if (m == 0) {
            return 0;
        }
        if (m == 1) {
            return 1;
        }
        Matrix A = new Matrix(2, 2);
        Matrix B = new Matrix(2, 1);
        A.value[0][0] = 1; A.value[0][1] = 1;
        A.value[1][0] = 1; A.value[1][1] = 0;
        B.value[0][0] = 1;
        B.value[1][0] = 0;
        return A.power(m - 1).multiply(B).value[0][0];    // f(n) = C(n)[0][0] = A^(n-1) B [0][0]
    }
    
    public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		System.out.println(fibonacci(n));
	}

我们将公式修改一下

 f(n) = 6 * f(n-1) + 5 * f(n-2) + n^2 + 6 * n + 5

同样的, 需要先找出 矩阵 A 和矩阵 B

同样的 C = AB, 我们需要找的 f(n) = C(n)[0][0]

我们拟构造一下

当 n = 2 和 n = 3 时,

矩阵A 需要做的 就是 n = 3 时 的结果 是 n=2 时的结果 和 矩阵A 相乘

n=3时:

    第一行:  f(2) = 6 * f(1) + 5 * f(0) + (2+1)^2 + 6 * 2 + 5

    第二行:  f(1) = n为2时的第一行

    第三行:  (2+1) ^ 2 = 2^2 + 2*2*1 + 1^2

    第四行:  2+1 = 2  +   1

    第五行:  1 = 1

体现在矩阵A 中:

我们模拟一下数据:

第一个数 f(0) : 0

第二个数 f(1) : 1

第三个数 f(2) : 27

第四个数 f(3) : 199

第五个数 f(4) : 1374

......

最后我们修改一下代码来实现

我们只需要修改一下矩阵A 和矩阵B就可以了, 带入刚刚推出来的矩阵A 和矩阵B

public static int fibonacci(int n) {
        int m = n - 1;
        if (m == 0) {
            return 0;
        }
        if (m == 1) {
            return 1;
        }        
        int[][] X = {
        		{6, 5, 1, 6, 5},
        		{1, 0, 0, 0, 0},
        		{0, 0, 1, 2, 1},
        		{0, 0, 0, 1, 1},
        		{0, 0, 0, 0, 1}
        };
        int[][] y = {
        		{1},
        		{0},
        		{4},
        		{2},
        		{1}
        };
        Matrix A = new Matrix(5, 5);
        Matrix B = new Matrix(5, 1);
        A.value = X;
        B.value = y;
        return A.power(m - 1).multiply(B).value[0][0];
    }

其他的地方不变

测试一下

第6个数 为 f(5) =  6 * f(4) + 5 * f(3) + 5^2 + 6 * 5 + 5 =  9299

缺陷: 当第n个数过大时, 使用int类型装不下会产生溢出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值