相信大家对于斐波那契数列已经很明白了,那就是前两位是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的矩阵)