求解斐波那契数列第 N N N项
对于求第 N N N项的值,可通过矩阵快速幂将时间复杂度降至 O ( l o g N ) O(logN) O(logN)。递归式 F ( N ) = F ( N − 1 ) + F ( N − 2 ) F(N)=F(N-1)+F(N-2) F(N)=F(N−1)+F(N−2),是一个二阶的递推数列,可用矩阵乘法表示,且状态矩阵为 2 × 2 2\times 2 2×2的矩阵:
( F ( n ) , F ( n − 1 ) ) = ( F ( n − 1 ) , F ( n − 2 ) ) × ∣ a b c d ∣ (F(n), F(n-1)) = (F(n-1),F(n-2)) \times \ \left| \begin{array}{cc} a & b\\ c & d\\ \end{array} \right| (F(n),F(n−1))=(F(n−1),F(n−2))× ∣∣∣∣acbd∣∣∣∣
把前4项代入, F ( 1 ) = = 1 , F ( 2 ) = = 1 , F ( 3 ) = = 2 , F ( 4 ) = = 3 F(1) == 1, F(2) == 1, F(3) == 2, F(4) == 3 F(1)==1,F(2)==1,F(3)==2,F(4)==3,可求出状态转移矩阵:
∣ a b c d ∣ = ∣ 1 1 1 0 ∣ \left| \begin{array}{cc} a & b\\ c & d\\ \end{array} \right| = \left| \begin{array}{cc} 1 & 1 \\ 1 & 0 \\ \end{array} \right| ∣∣∣∣acbd∣∣∣∣=∣∣∣∣1110∣∣∣∣
当 n > 2 n > 2 n>2时,
( F ( 3 ) , F ( 2 ) ) = ( F ( 2 ) , F ( 1 ) ) × ∣ 1 1 1 0 ∣ = ( 1 , 1 ) × ∣ 1 1 1 0 ∣ ( F ( 4 ) , F ( 3 ) ) = ( F ( 3 ) , F ( 2 ) ) × ∣ 1 1 1 0 ∣ = ( 1 , 1 ) × ∣ 1 1 1 0 ∣ 2 ⋮ ( F ( n ) , F ( n − 1 ) ) = ( F ( n − 1 ) , F ( n − 2 ) ) × ∣ 1 1 1 0 ∣ = ( 1 , 1 ) × ∣ 1 1 1 0 ∣ n − 2 (F(3), F(2)) = (F(2),F(1)) \times \ \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right| = (1, 1) \times \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right| \\ (F(4), F(3)) = (F(3),F(2)) \times \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right| = (1, 1) \times \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right|^2 \\ \vdots \\ (F(n), F(n-1)) = (F(n-1),F(n-2)) \times \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right| = (1, 1) \times \left| \begin{array}{cc} 1 & 1\\ 1 & 0\\ \end{array} \right|^{n-2} (F(3),F(2))=(F(2),F(1))× ∣∣∣∣1110∣∣∣∣=(1,1)×∣∣∣∣1110∣∣∣∣(F(4),F(3))=(F(3),F(2))×∣∣∣∣1110∣∣∣∣=(1,1)×∣∣∣∣1110∣∣∣∣2⋮(F(n),F(n−1))=(F(n−1),F(n−2))×∣∣∣∣1110∣∣∣∣=(1,1)×∣∣∣∣1110∣∣∣∣n−2
所以,求解原问题转变为如何求解矩阵的 N N N次幂,这就可以利用矩阵快速幂,时间复杂度为 O ( l o g N ) O(logN) O(logN)。矩阵快速幂与普通快速幂并无本质区别,只是把普通乘法换成了矩阵乘法。下面举个例子说明普通快速幂如何快速计算。
假设求解10的75次方:
1.75的二进制数形式为1001011。
2.10的75次方为 1 0 64 × 1 0 8 × 1 0 2 × 1 0 1 10^{64}\times 10^8 \times 10^2 \times 10^1 1064×108×102×101。
我们先求出 1 0 1 10^1 101,然后根据 1 0 1 10^1 101求出 1 0 2 10^2 102,再根据 1 0 2 10^2 102求出 1 0 4 10^4 104, . . . . . . ...... ......,最后根据 1 0 32 10^{32} 1032求出 1 0 64 10^{64} 1064。也就是说,75二进制表示有多少位,我们就做了多少次乘法。
public int[][] matrixPower(int[][] m, int p){
int[][] res = new int[m.length][m[0].length];
//先把res初始化为单位矩阵
for (int i = 0; i < res.length; i++){
res[i][i] = 1;
}
int[][] tmp = m;
for (; p != 0; p >>= 1){ //右移符号,相当于整除2
if ((p&1) != 0){
res = muliMatrix(res, tmp);
}
tmp = muliMatrix(tmp, tmp);
}
return res;
}
public int[][] muliMatrix(int[][] m1, int[][] m2){
int[][] res = new int[m1.length][m2[0].length];
for (int i = 0; i < m2[0].length; i++){
for (int j = 0; j < m1.length; j++) {
for (int k = 0; k < m2.length; k++){
res[i][j] += m1[i][k] * m2[k][j];
}
}
}
return res;
}
使用矩阵快速幂求解斐波那契数列第 N N N项的过程如下:
public int calc(int n){
if (n < 1) {
return 0;
}
if (n == 1 || n == 2){
return 1;
}
int[][] base = {{1, 1} , {1, 0}};
int[][] res = matrixPower(base, n - 2);
return res[0][0] + res[1][0];
}
如果递归式严格符合 F ( n ) = a × F ( n − 1 ) + b × F ( n − 2 ) + . . . + k × F ( n − i ) F(n) = a \times F(n-1) + b\times F(n-2) + ... + k\times F(n-i) F(n)=a×F(n−1)+b×F(n−2)+...+k×F(n−i),那么它就是一个 i i i阶的递推式,必然有与 i × i i \times i i×i的状态矩阵有关的矩阵乘法的表达。一律可用矩阵快速幂将时间复杂度降至 O ( l o g N ) O(logN) O(logN)。