斐波那契数列中的神秘定理

相信大家对于斐波那契数列已经很明白了,那就是前两位是1,而后面的每一位都等于前面两项之和,也就是

F(n) = F(n-1) + F(n-2)

而这个通项公式也经常作为我们初次接触递归函数时的练手例子,比如如下代码:

public static int f1(int n){
		if (n < 1) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		return f1(n - 1) + f1(n - 2);
}

那么随着我们对计算速度要求的提高,这种暴力递归已经无法满足我们的需求,于是我们接触到了空间换时间大法——动态规划,只需要把每次计算的内容存在一个表里,那以后就可以直接用,而不需要重复计算,同时这也是对我们算法能力提升的一个重要路口,这里使用一个迭代计算的方法,代码改写如下:

public static int f2(int n) {
		if (n < 1) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		int res = 1;
		int pre = 1;
		int tmp = 0;
		for (int i = 3; i <= n; i++) {
			tmp = res;
			res = res + pre;
			pre = tmp;
		}
		return res;
	}

代码比较简单,使用三个变量存储前两个值以及答案本身,就可以把他算出来,那么,你有没有想过仅仅使用O(log N) 的方法就搞定它呢?而这也就是斐波那契数列隐含的一种数学规律了。下面开始讲解:

我们知道斐波那契数列的通项: F(n) = F(n-1) + F(n-2)

而在线性代数中,有如下规律:对于递推式严格稳定并且不随着条件有所改变的话,这个数列满足

| F(n) F(n-1) | = | F(n-1) F(n-2) | * (一个2*2的矩阵)

相信学过线性代数的朋友们能理解上面的内容,而由于递推式系数严格不随条件改变,那这个矩阵就是固定唯一的,经过计算,这个二阶矩阵时{ {1,1} , {1,0} },大家可以随意带入数列项进去验算,那么既然如此,我们可以得出:

| F(n) F(n-1) | = | F(2) F(1) | * { {1,1} , {1,0} }的n-2次方!

等价于| F(n) F(n-1) | = | 1 1| * { {1,1} , {1,0} }的n-2次方!

得到这一步可真是太有用了,因为这个公式里面只要想办法让矩阵的自我乘方足够快就好,而我们万能的二进制可以帮助我们,我们把n-2转化成二进制,每次迭代只需要相乘自己并且只需要判断是否和答案相乘即可,接下来上代码:

public static int f3(int n) {
		if (n < 1) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		// [ 1 ,1 ]
		// [ 1, 0 ]
		int[][] base = { 
				{ 1, 1 }, 
				{ 1, 0 } 
				};
		int[][] res = matrixPower(base, n - 2);
		return res[0][0] + res[1][0];
	}

	public static int[][] matrixPower(int[][] m, int p) {
		int[][] res = new int[m.length][m[0].length];
//初始化一个对角单位阵作为初试
		for (int i = 0; i < res.length; i++) {
			res[i][i] = 1;
		}
		
		// res = 矩阵中的1
		int[][] tmp = m;// 矩阵1次方
		for (; p != 0; p >>= 1) {
			if ((p & 1) != 0) {
				res = muliMatrix(res, tmp);
			}
			tmp = muliMatrix(tmp, tmp);
		}
		return res;
	}

	// 两个矩阵乘完之后的结果返回
	public static int[][] muliMatrix(int[][] m1, int[][] 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++) {
					res[i][j] += m1[i][k] * m2[k][j];
				}
			}
		}
		return res;
	}

推广:任何满足

fn = aF(n-1)+bF(n-2)+cF(n-i)…的严格递推式都可以表示为

| F(n) F(n-1)…F(n-i) | = |F(i)… F(2) F(1) | * (一个i*i的矩阵)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值