原理:
斐波那契数列定义
用矩阵形式来描述递推关系:
以上递推式可以写成矩阵形式:
观察结果
例如F(2) = 1, F(3) = 2...
而实际上f(n)就是矩阵的左上角元素就是斐波那契数列的第n项的值
此矩阵指下面的递推关系矩阵
普通的乘方算法
现在讨论矩阵的乘方。我们举一个例子,计算 A^10 。通常的运算是这样的:
A*A*A*A*A*A*A*A*A*A
我们发现,上述方法需要使用 9 次乘法运算才能够算出 A^10。一般而言,为计算A^10 ,用上述方法需要 N−1 次乘法才可以。那能不能改进呢?
快速幂算法
我们采用二分的策略优化它。具体如下所示:
T1=A*A; //此时算到A^2
T2=T1*T1; //此时算到A^4
T3=T2*T2; //此时算到A^8
T4=T3*T1; //此时算到A^10,结束,返回T4
我们发现,按照这种方法去计算,仅仅用了 4 次乘法运算就能算出 A^10 。
我们把如上算法一般化。 下面使用自顶向下的递归方法:
计算 A^n:
设M=A^(n/2); //其中n/2向下取整
如果n=1:
返回递推关系矩阵 (1,1,1,0)
如果n是偶数:
返回M*M;
如果n是奇数:
返回M*M*M;
递归与矩阵快速幂的总结
1. 递归方法:
优点:
- 实现简单,直观,易于理解。
- 适用于小规模问题,对于小输入可以快速计算。
缺点:
- 递归会产生大量重复计算,效率较低。
- 时间复杂度为 (O(2^n)),指数级增长,导致性能在 (n) 增加时急剧下降。
- 对于大规模输入,递归可能会导致堆栈溢出。
2. 矩阵快速幂方法:
优点:
- 提高了计算效率,特别适用于大规模问题。
- 时间复杂度为 (O(\log n)),具有较高的效率。
- 避免了重复计算,提高了性能。
缺点:
- 实现稍复杂,需要理解矩阵乘法和矩阵幂的算法。
3.比较总结:
- 在小规模问题上,递归可能更直观,但在大规模问题上,矩阵快速幂明显更快。
- 矩阵快速幂通过降低时间复杂度解决了递归中的重复计算问题,大大提高了效率。
- 递归通常更易实现,但可能会受到堆栈溢出和指数级增长的时间复杂度影响。
- 根据问题规模选择适当的方法,对于斐波那契数列等递推问题,矩阵快速幂是更为高效的选择。
完整代码:
import java.time.Instant;
public class Fibonacci {
public static void main(String[] args) {
final Instant startTime = Instant.now();
int n = 40; // 更改为您要查找的斐波那契数列的位置
long result = fibonacciMatrix(n);
final Instant endTime = Instant.now();
System.out.println("第 " + n + " 位斐波那契数是:" + result);
System.out.println("耗时:" + (endTime.toEpochMilli() - startTime.toEpochMilli()) + " ms");
}
// 定义一个2x2的矩阵类
static class Matrix {
long a, b, c, d;
Matrix(long a, long b, long c, long d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
// 矩阵相乘
Matrix multiply(Matrix other) {
long newA = a * other.a + b * other.c;
long newB = a * other.b + b * other.d;
long newC = c * other.a + d * other.c;
long newD = c * other.b + d * other.d;
return new Matrix(newA, newB, newC, newD);
}
@Override
public String toString() {
return "Matrix:\n" +
"|" + a +
", " + b +" |"+
"\n|" + c +
", " + d +" |";
}
}
// 快速幂算法计算斐波那契数列
public static long fibonacciMatrix(int n) {
if (n <= 1) {
return n;
}
Matrix result = power(new Matrix(1, 1, 1, 0), n - 1);
System.out.println(result.toString());
return result.a;
}
// 快速幂算法
private static Matrix power(Matrix matrix, int n) {
if (n == 1) {
return matrix;
}
if (n % 2 == 0) {
Matrix half = power(matrix, n / 2);
return half.multiply(half);
} else {
Matrix half = power(matrix, n / 2);
return matrix.multiply(half).multiply(half);
}
}
}
当然如果需要求更大位数的值时,需要使用java的大数类去运算,否则会超出界限