有关矩阵快速幂的题都记录在此,持续更新~
文章目录
笔记
矩阵快速幂原理:
如果现在要算X8
- 一般思路:
即XXXXXXXX一个一个往上面乘,则乘法运算进行7次。- 换个思路:
采用(XX)(XX)(XX)(XX)这种求法,先进行乘法得X2,然后对X2再执行三次乘法,这样乘法运算执行4次。已经比七次要少。- 快速幂思路:
快速幂思路和上一个思路类似,就是划分乘法,使得总乘法次数尽可能少。现在要考虑应该怎么分让计算比较快。快速幂采用的则是二进制的加权划分方法:例如计算X19次方。
19的二进制为:1 0 0 1 1 。
每个二进制位对应一个权值:X2(n-1),对于每个不为0的位,我们将他们乘起来:即X19 = (X16)(X2)(X1)
这样我们每计算一个权值都可以直接利用上一个权值(上一个权值的平方),大大减少了乘法次数。
//代码模板
static int fastmul(int pow,int num){
int ans=1;
while(pow>0){
if((pow&1)!=0){
ans*=num;
}
pow>>=1;
//计算权值
num=num*num
}
return ans;
}
想实现矩阵快速幂,则把上诉乘法改为矩阵乘法,初始化的ans改为单位矩阵即可。下面定义一个实现矩阵乘法的方法:
//输入矩阵必须满足n*m 和m*k尺寸,输出矩阵为n*k
static int[][] mul(int m1[][],int m2[][]) {
int ans[][]= new int[m1.length][m2[0].length];
for (int i = 0; i < ans.length; i++) {
for (int j = 0; j < ans[0].length; j++) {
for (int k = 0; k < ans.length; k++) {
//想了好久才反应过来,读者自己脑补思考下这些下标
ans[i][j]+=m1[i][k]*m2[k][j];
}
}
}
return ans;
}
1137.第N个泰波那契数
泰波那契序列 Tn 定义如下: T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn +Tn+1 + Tn+2 给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
- 解题思路:
找递推,构造矩阵必须为方阵
∣ a 0 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 ∣ ∣ f ( n ) f ( n − 1 ) f ( n − 2 ) ∣ = ∣ f ( n − 2 ) + f ( n − 1 ) + f ( n ) f ( n ) f ( n − 1 ) ∣ = ∣ f ( n + 1 ) f ( n ) f ( n − 1 ) ∣ \begin{vmatrix} a0&a1&a2\\ a3&a4&a5\\ a6&a7&a8 \end{vmatrix} \begin{vmatrix} f(n)\\ f(n-1)\\ f(n-2) \end{vmatrix} = \begin{vmatrix} f(n-2)+f(n-1)+f(n)\\ f(n)\\ f(n-1) \end{vmatrix} = \begin{vmatrix} f(n+1)\\ f(n)\\ f(n-1) \end{vmatrix} ∣∣∣∣∣∣a0a3a6a1a4a7a2a5a8∣∣∣∣∣∣∣∣∣∣∣∣f(n)f(n−1)f(n−2)∣∣∣∣∣∣=∣∣∣∣∣∣f(n−2)+f(n−1)+f(n)f(n)f(n−1)∣∣∣∣∣∣=∣∣∣∣∣∣f(n+1)f(n)f(n−1)∣∣∣∣∣∣
容易解得矩阵为
∣ 1 1 1 1 0 0 0 1 0 ∣ \begin{vmatrix} 1&1&1\\ 1&0&0\\ 0&1&0 \end{vmatrix} ∣∣∣∣∣∣110101100∣∣∣∣∣∣
所以
∣ f ( n ) f ( n − 1 ) f ( n − 2 ) ∣ = ∣ 1 1 1 1 0 0 0 1 0 ∣ n − 2 ∣ f ( 2 ) f ( 1 ) f ( 0 ) ∣ \begin{vmatrix} f(n)\\ f(n-1)\\ f(n-2) \end{vmatrix} = \begin{vmatrix} 1&1&1\\ 1&0&0\\ 0&1&0 \end{vmatrix}^{n-2} \begin{vmatrix} f(2)\\ f(1)\\ f(0) \end{vmatrix} ∣∣∣∣∣∣f(n)f(n−1)f(n−2)∣∣∣∣∣∣=∣∣∣∣∣∣110101100∣∣∣∣∣∣n−2∣∣∣∣∣∣f(2)f(1)f(0)∣∣∣∣∣∣
最后用矩阵快速幂计算就可以。 - Java,还提供了另外一些方法:
public class 第N个泰波那契数1137 {
//暴力,超时
static int dfs(int n) {
if(n==0)return 0;
if(n==1)return 1;
if(n==2)return 1;
return dfs(n-1)+dfs(n-2)+dfs(n-3);
}
//滑动窗口
static class Solution0 {
public int tribonacci(int n) {
if(n==0)return 0;
if(n<=2)return 1;
int win[]={0,1,1};
for (int i = 3; i <= n; i++) {
//计算下一项
int ans=win[0]+win[1]+win[2];
//窗口更新
win[0]=win[1];
win[1]=win[2];
win[2]=ans;
}
return win[win.length-1];
}
}
//矩阵快速幂
static class Solution {
//首先写个矩阵乘法的函数,输入矩阵必须满足n*m 和m*k尺寸,输出矩阵为n*k
static int[][] mul(int m1[][],int m2[][]) {
int ans[][]= new int[m1.length][m2[0].length];
for (int i = 0; i < ans.length; i++) {
for (int j = 0; j < ans[0].length; j++) {
for (int k = 0; k < ans.length; k++) {
//想了好久才反映过来
ans[i][j]+=m1[i][k]*m2[k][j];
}
}
}
return ans;
}
//快速幂方法
static int[][] fast(int pow,int m[][]) {
//初始化一个单位矩阵
int ans[][]={{1,0,0},{0,1,0},{0,0,1}};
while (pow>0) {
//取末位,不为0,则计算中间结果
if ((pow&1)!=0) {
//答案乘以此位中间结果
ans=mul(ans, m);
}
//右移一位
pow=pow>>1;
//计算此位的中间结果
m=mul(m, m);
}
return ans;
}
//计算斐波那契
static int tribonacci(int n) {
if (n == 0) return 0;
if (n <= 2) return 1;
int m[][]= {{1,1,1},
{1,0,0},
{0,1,0}};
int first[][]= {{1},{1},{0}};
//注意这里
int mn[][]=mul(fast(n-2, m),first);
return mn[0][0];
}
}
public static void main(String[] args) {
Solution s=new Solution();
System.out.println(s.tribonacci(25));
}
}