类斐波那契数列问题

首先说明 这种解法并不能解决带条件转移方程的问题

对于斐波那契数列来说

我们有

解法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

你可能感兴趣的:(算法)