今天看《剑指offer》看到一个递推关系:f(n) = f(n-1) + f(n-2). 书中提出了一种简单的算法,也就是矩阵乘法:
如果是n次方,那么时间复杂度应该是O(n). 那么有没有一种更快的算法呢?快速幂算法能让时间复杂度降至O(logn).
怎么来做快速幂算法呢?我们首先先想一个简单的,一个数字a,求他的75次幂。75的二进制是1001011 ,所以实际上a^75 = a^64 * a^8 * a^2 *a^1. 我们把它分解成整数指数次幂的积的形式。怎么乘呢?
int a = 4, m = 75;
int power2num = n;
int result = 1;
while(m != 0) {
// 只有当最低位为1时,结果才乘上现在的值,
if ((m & 1) != 0)
result *= power2num;//这模拟的是a^t,t是二进制m中为1的位
// 每移位一次,幂方计算一次
power2num *= power2num;
m >>= 1;
}
看明白了吧,result模拟的是每个75中为1的位所代表的的a^t这一位。每次移位power2num都需要乘以自己。
那么矩阵是同理的。我们这里写了两个函数,一个单独处理矩阵的乘法,另一个是求幂:
public long[][] matrixMult(long[][] a, long[][] b) {//求矩阵乘法
// a的列必须与b的行相等
assert a.length == b[0].length;
int n = a.length, m = a[0].length, p = b[0].length;
long[][] result = new long[n][p];
//矩阵乘法的基本方式为三层循环
for(int i=0; i<n; i++) {
for(int j=0; j<p; j++) {
for(int k=0; k<m; k++) {
result[i][j] += a[i][k] * b[k][j];
}
}
}
return result;
}
public long[][] matrixPower(long[][] matrix, int p) {//求幂函数
//result存放结果,注意m*n x n*t的矩阵维度结果是m*t
long[][] result = new long[matrix.length][matrix[0].length];
for(int i=0; i<result.length; i++) {//result先是全1矩阵
result[i][i] = 1;
}
long[][] pingfang = matrix;//复制matrix
for(; p != 0; p >>= 1) {
if((p & 1) != 0) {
// 注意result在前面
result = matrixMult(result, pingfang);
}
pingfang = matrixMult(pingfang, pingfang);
}
return result;
}
通过这两个函数就可以迅速求出一个矩阵的n次方了。斐波那契数列那道题,这个2x2矩阵应该是【11】
【10】