LeetCode刷题:矩阵快速幂

有关矩阵快速幂的题都记录在此,持续更新~

笔记

矩阵快速幂原理:

如果现在要算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} a0a3a6a1a4a7a2a5a8f(n)f(n1)f(n2)=f(n2)+f(n1)+f(n)f(n)f(n1)=f(n+1)f(n)f(n1)
    容易解得矩阵为
    ∣ 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(n1)f(n2)=110101100n2f(2)f(1)f(0)
    最后用矩阵快速幂计算就可以。
  • Java,还提供了另外一些方法:
public classN个泰波那契数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));
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hilbob

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值