概述
斐波那契数列问题就是已知递推式F(n) = F(n-1)+F(n-2),给出n,求F(n)的问题。一般给了范围后直接打表即可,这种方法我也不说了,本文主要研究利用矩阵乘法加速求解斐波那契数列的算法。
思路分析
我们先来了解一下做这道题的前置知识——矩阵乘法:
只需要这个简单的就足够了...,下面开始分析如何将斐波那契数列应用矩阵乘法做一个变形。
我们已知F(1)=1,F(2)=1,F(3)=2,F(4)=3...。将其带入公式:
当n=3时:
当n=4时:
由此可推出一般式:
从此,题目就变成了快速求矩阵的N次方问题,矩阵求幂运算和数字求幂运算大体相同,不了解数字快速幂的同学可以访问这里:传送门。
代码
package data_structure;
import org.junit.Test;
public class Fibonacii {
/**
* 求两矩阵相乘
*
* @param p
* @param q
* @return 结果矩阵
*/
public int[][] matrixMulti(int[][] p, int[][] q) {
int[][] res = new int[p.length][q[0].length];
for (int i = 0; i < p.length; i++) {
for (int j = 0; j < q[0].length; j++) {
for (int k = 0; k < q.length; k++) {
res[i][j] += (p[i][k] * q[k][j]);
}
}
}
return res;
}
/**
* 求幂运算
*
* @param m
*/
public int[][] matrixPow(int[][] m, int n) {
int[][] res = new int[m.length][m[0].length];
for (int i = 0; i < res.length; i++) {
res[i][i] = 1;
}
int[][] temp = m;
while (n != 0) {
if ((n & 1) != 0) {
res = matrixMulti(temp, res);
}
temp = matrixMulti(temp, temp);
n >>= 1;
}
return res;
}
//此方法与matrixPow作用相同
public int[][] matrixPow1(int[][] m, int n) {
if (n == 0) {
return m;
} else if ((n & 1) == 0) {
return matrixMulti(m, matrixPow1(m, n - 1));
} else {
int[][] temp = matrixPow1(m, n >> 1);
return matrixMulti(temp, temp);
}
}
public int fibonacii(int n) {
if (n == 0) {
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
int[][] base = { { 1, 1 }, { 1, 0 } };
int[][] res = matrixPow(base, n - 2);
return res[0][0] + res[1][0];
}
@Test
public void main() {
for (int i = 0; i < 10; i++)
System.out.println(fibonacii(i));
}
}
总结
一个的算法就出来了,对于F(N)=F(N-1)+F(N-2)来说,所需矩阵是一个2*2的,在进行矩阵乘法代码相当于常数时间内完成,进行矩阵幂运算时,时间复杂度为,所以整体时间复杂度为。