本文已参与「新人创作礼」活动,一起开启掘金创作之路。
矩阵快速幂
常规求幂
求的值,如果用纯for循环,要循环n次乘a。 时间复杂度:O(n) 空间复杂度:S(1)
递归
与二分法异曲同工。 例:
只需要将幂次二分,取平方(再乘a)即可。
时间复杂度:O(logn) 空间复杂度:O(logn)
快速幂
对n进行二进制分解。 例:求解
- 将57转为二进制
111001,对二进制为1的位取值,即 - 求每位二进制的值:
- 初始化
a = 1 - 从低位起,每位二进制值为
a *= a
- 初始化
- 将二进制为1的位取值相乘。
public int MOD = 1000000007;
public static int qp(int a, int n) {
int ans = 1;
while (n > 0) {
if ((n&1) == 1) {
ans = (int) (((long)ans * a) % MOD);
}
a = (int) (((long)a * a) % MOD);
n >>= 1;
}
return ans;
}
矩阵快速幂
矩阵乘法求解递归状态转移
以求解斐波那契数列为例
利用矩阵乘法
设定矩阵为A
则可以分解最终矩阵为
确定矩阵A
任意状态转移方程均可确定矩阵A,例:
java 代码实现
public static int[][] matrix_qp(int n) {
//以斐波那契数列为例
//矩阵A
//0 1
//1 1
int[][] A = new int[2][2];
A[0][0] = 0;
A[0][1] = A[1][0] = A[1][1] = 1;
//斐波那契数列0 1矩阵
//1 0
//1 0
int[][] F = new int[2][2];
F[0][0] = F[1][0] = 1;
F[0][1] = F[1][1] = 0;
return matrix_multi(matrix_mi(A, n), F);
}
public static int[][] matrix_multi(int[][] a, int[][] b) {
int[][] ans = new int[2][2];
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
ans[i][j] += a[i][k] * b[k][j];
return ans;
}
public static int[][] matrix_mi(int[][] a, int n) {
int[][] ans = new int[2][2];
ans[0][0] = ans[1][1] = 1;
while(n > 0) {
if ((n&1) == 1)
ans = matrix_multi(ans, a);
a = matrix_multi(a, a);
n >>= 1;
}
return ans;
}
public static void show_matrix(int[][] a) {
System.out.println("Matrix");
for (int i = 0; i < a.length; ++i) {
for (int j = 0; j < a[i].length; ++j)
System.out.print(a[i][j] + " ");
System.out.println();
}
}
上述代码未作模运算。
做模运算时需注意:
当矩阵包含负数时,要保证被模数大与0
(a%c - b%c + c)%c