Fibanacci 的复杂度O(logn)方式
快速幂
快速幂图解
根据上面的链接
在求幂的时候 暴力算法是不停的乘本身A 需要很多次的调用自己本身 乘很多次 时间复杂度高
但是所采用“分治法”将
1.多次幂运算乘以自己这个大问题分成若干的小问题
2.然后递归解决每一个小问题
3.合并子问题的解成大问题的解
如果n是偶数
An=A(n/2)*A^(n/2)
n是奇数
An=A(a=(n-1)/2)*A^((n-1)/2)*A
- 快速幂又在上面基础上升级用二进制,我心里认为为什么要转二进制呢 ?
- 就是最容易“分” 十进制都可以变为二进制嘛这样二进制的每一位就对应着一个子问题
-又最容易 “治” ,所有的子问题都可以继续递归 因为你2^15一定可以从2 ^12得来 就是说2的次幂是叠着乘的 后面的结果就是前面结果乘2获得的
分治法让相乘次数减少 举例:*
这样A^4=AAAA 需要3次乘操作
现在A^4=A * A(第一次乘操作) x (AA)
只需要两次乘操作 A * *A 第一次乘操作然后结果作为一个整体 再次乘以自己 (A * A) *(A *A) 只需要2次乘法
44次相乘—》5次相乘
什么要把10进制转为2进制呢?(对上下这两个图的解说,请参看)
首先二进制不是1就是0,上面我们把A^n拆分那到底会被拆分成那些子问题相乘 二进制一目了然 该位为1就会归并到答案中作为子问题合并 该位为0就不理会
- 我们从二进制最后一位开始看是1还是0,
与1操作能判断右移后新的最后一位原理:
从最后一位看因为最后一位是2^0=1 所有的后面的子问题也都是从他相乘的来的 一定要从他开始的 - 看完是1还是0选择时候归入答案
- 进行自己乘自己的操作 不管你是1还是0都自乘 这里可不是考虑归并答案的阶段 这里是中间结果给下一位用的 你不自乘 到下一位人家应该获得相应位置的次幂 人家得不到
下图所示 第二位1在二进制对应的次幂就是4次幂
你第一位0没自乘 人家得到的就是1次幂的 所以你得自乘下一位对应的幂数才得到了
第一行b转为二进制
第二行a的b次幂可以变成这种合适
第三行每次求完一位要翻倍a给下一位使用
矩阵乘法
public static int[][] muliMatrix(int[][] m1, int[][] m2) {
//构造出一个m1行和m2列的矩阵(矩阵相乘规则)
int [][] res = new int[m1.length][m2[0].length];
//给我们要得到的矩阵的每一个元素的值进行赋值操作
for(int i = 0; i < m1.length; i++) {
for(int j = 0; j < m2[0].length; j++) {
for(int k = 0; k < m2.length; k++) {
//i,j位置元素的值就是i行元素和j行元素乘积的加和
res[i][j] += m1[i][k] * m2[k][j];
}
}
}
return res;
}
矩阵快速幂
//求矩阵m的p次幂的值
public static int[][] matrixPower(int[][] m, int p){
int [][] res = new int[m.length][m[0].length];
//先把res设为单位矩阵,相当于整数中的1 单位矩阵和m的规模一样大 对角线为1 其余为0
//【1,0】 二阶单位矩阵 若m为三阶 res也跟着变换
// 【0,1】
for (int i = 0; i < res.length; i++) {
res[i][i] = 1;
}
System.out.println("单位矩阵");show(res);
//临时矩阵
int [][] tmp = m;
for (; p != 0; p >>= 1) {
if ((p & 1) != 0) {
//按位与操作,此位为奇数放进结果中
res = muliMatrix(res, tmp);
}
//每次都要自己乘方自己 给下一次使用 翻转值
tmp = muliMatrix(tmp, tmp);
}
return res;
}
fibnacci通过数学归纳法推出的矩阵快速幂公式