首先说明 这种解法并不能解决带条件转移方程的问题
对于斐波那契数列来说
我们有
解法1:
最暴力的解法 递归 第N个位置的值是由N-1 N-2位置的值相加而来
解法2:
这是解法1的优化解法 通过dp数组 减少重复计算
解法3:
这是我们要讲解的重点
N位置的值F(N)满足以下等式
F(N) = F(N-1) + F(N-2)
先说结论
对于 F(N) = c1F(N-1)+c2F(N-2).....+ckF(N-k);
c1 c2 ... ck 都为任意常数
那么可以看做k阶问题
假如说3阶问题 就有[F(4),F(3),F(2)] = [F(3),F(2),F(1)] * (3*3矩阵)
[F(5),F(4),F(3)] = F[(4),F(3),F(2)] * (3*3矩阵)
....
四阶问题
[F(5),F(4),F(3),F(2)] = [F(4),F(3),F(2),F(1)] * (4*4矩阵)
[F(6),F(5),F(4),F(3)] =[F(5),F(4),F(3),F(2)] * (4*4矩阵)
....
所以我们可以看出斐波那契数列问题 满足递推式且是个二阶问题
也就是说 [F(N),F(N-1)] = [F(N-1),F(N-2)]*(2*2矩阵)
也就可以从[F(3),F(2)] = [F(2),F(1)]*(2*2矩阵) 一步一步累乘出来
其实就是 [F(N),F(N-1)] = [F(2),F(1)]* (矩阵的N-2次方)
但是 对于N来说 我们要计算N-2次矩阵乘法才能出结果 这个复杂度也不小
我们来看一个引例
10的75次方怎么算最快呢
我们把75拆成二进制 1001011
1001011 = 0000001 + 0000010 + 0001000 + 1000000
也就是10的1001011次方 = 10的0000001次方 * 10的0000010次方 * 10的0001000次方 * 10的1000000次方
所以我们需要找到每一个二进制中的1的 位置 然后求出对应的值 然后乘在一起
这里面还有一个优化 因为是二进制 所以10的001次方 乘以10的001次方 就等于 10的010次方
也就是十进制的1 2 4 8 16次幂对应着二进制的 0001 0010 0100 1000 这样子
10的1次幂*10的1次幂 为 10的二次幂 10的二次幂*10的二次幂为10的四次幂 这样一直用自身乘自身 就能遍历完二进制的每一位
然后再看我们的1001011 如果对应位上为1 那就把当前值乘入结果 如果为0 就不乘入结果
....
对于[F(2),F(1)]* (矩阵的N-2次方)来说 也是如此
把N-2拆成二进制 一步步累乘 如果有效就乘进结果 无效就不乘
不过这里面隐含着一个条件 当10的0次幂时 就是说最开始是有个1的 那我们矩阵在最开始也应该有一个对应的单位矩阵作为basecase
3*3的单位矩阵为 1 0 0
0 1 0
0 0 1
来看一道例题
刚开始有一只母牛 然后母牛每年生一头小母牛 小母牛三年能参与生产 问N年后有多少母牛
F(N) = F(N-1) + F(N-3) 对吧N年的牛的数量 = 去年牛的数量 + 三年前牛的数量(三年前牛的数量是 一定可以参加生产的数量 如果是1年前 两年前的牛 那里面就含有还不能生产的小牛的数量)
public static int mymethod(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2 || n == 3) {
return n;
}
int[][] base = {
{ 1, 1, 0 },
{ 0, 0, 1 },
{ 1, 0, 0 } };
int[][] res = matrixPower(base, n - 3);
return 3 * res[0][0] + 2 * res[1][0] + res[2][0];//只求三个参数中第一个就可以了
}
public static int[][] mymatrixPower(int [][] base,int N){
int [][] res = new int[base.length][base[0].length];
for(int i = 0;i >=1) {
if((N&1)!=0) {
res = mymuliMatrix(res,tmp);
}
tmp = mymuliMatrix(tmp,tmp);
}
return res;
}
public static int[][] mymuliMatrix(int[][] m1, int[][] m2) {
int [][] res = new int [m1.length][m2[0].length];
for(int i = 0;i