目录
1.斐波那切数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。
斐波那契数列代码实现:
//第一种解法
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;
}
我们观察数列:1、1、2、3、5、8、13、21、34...可以得到: F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*),转化为行列式规律为:
| 1 1 |n-2
|F(n),F(n-1)| = |F(2),F(1)| * | | 其中F(2)=1,F(1)=1。
| 1 0 |
代码实现为:
//解法三
// O(logN)
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);
//若: | 1 1 |n-2 | x y |
// | | = | | 则:F(n) = x+z,这里的x为:
// | 1 0 | | z k | res[0][0] y为:res[1][0]
return res[0][0] + res[1][0];
}
//求一个矩阵的p次方
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 = product(res, tmp);
}
tmp = product(tmp, tmp);
}
return res;
}
// 两个矩阵乘完之后的结果返回
public static int[][] product(int[][] a, int[][] b) {
int n = a.length;
int m = b[0].length;
int k = a[0].length; // a的列数同时也是b的行数
int[][] ans = new int[n][m];
for(int i = 0 ; i < n; i++) {
for(int j = 0 ; j < m;j++) {
for(int c = 0; c < k; c++) {
ans[i][j] += a[i][c] * b[c][j];
}
}
}
return ans;
}
2.应用1
问题:楼梯上有n阶台阶,上楼时可以一步上1阶,也可以一步上两阶,编写算法计算共有多少种不同的上楼梯的方法。
为什么说上楼梯问题是斐波那契数列的应用呢?我们可以先列举n比较小的时候。
n=1:只有 {1} 一种(1)
n=2:可以有 {1 1} 和2 两种(2)
n=3:可以有 {1 2} 和 {2 1} 和{1 1 1} 三种(3)
n=4:可以有{2 2} 和{1 1 2} 和{1 2 1} 和{2 1 1}和 {1 1 1 1} 五种(5)
…
代码实现:
public static int s1(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2) {
return n;
}
return s1(n - 1) + s1(n - 2);
}
public static int s2(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2) {
return n;
}
int res = 2;
int pre = 1;
int tmp = 0;
for (int i = 3; i <= n; i++) {
tmp = res;
res = res + pre;
pre = tmp;
}
return res;
}
public static int s3(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2) {
return n;
}
int[][] base = { { 1, 1 }, { 1, 0 } };
int[][] res = matrixPower(base, n - 2);
return 2 * res[0][0] + res[1][0];
}
3.应用2
问题:一个农夫养了一头牛,三年后,这头牛每年会生出1头牛,生出来的牛三年后,又可以每年生出一头牛……问农夫10年后有多少头牛?n年呢?
代码实现:
public static int c1(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2 || n == 3) {
return n;
}
return c1(n - 1) + c1(n - 3);
}
public static int c2(int n) {
if (n < 1) {
return 0;
}
if (n == 1 || n == 2 || n == 3) {
return n;
}
int res = 3;
int pre = 2;
int prepre = 1;
int tmp1 = 0;
int tmp2 = 0;
for (int i = 4; i <= n; i++) {
tmp1 = res;
tmp2 = pre;
res = res + prepre;
pre = tmp1;
prepre = tmp2;
}
return res;
}
// 1 2 3 4 6 9 13
// F(n) = 1 * F(n-1) + 0 * F(n-2) + 1 * F(n-3)
// | 1 1 0 |n-3
// |F(n),F(n-1),F(n-2)| = |F(3),F(2),F(1)| * | 0 0 1 |
// | 1 0 0 |
public static int c3(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];
}
4.总结
斐波那切数列使用条件:除了初始条件,没有条件转移 。
普遍一般规律:
| ... |n-k
|F(n),F(n-1),...,F(n-k+1)| = |F(k),...,F(2),F(1)| * | k * k |
| ... |