题目
题目:定义Fibonacci 数列如下:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+f(n-2) n=2
8
输入n,用最快的方法求该数列的第n 项。
要求时间复杂度为Olog(n)
解题思路
前人文章:http://zhedahht.blog.163.com/blog/static/25411174200722991933440/
问题转化为求下面的公式
这个2×2的矩阵用一个矩阵对象表示。里面有4个属性,分别表示f(n),f(n-1),f(n-1),f(n-2),求f(n)就是得到第一个属性的值。
求矩阵的公式,采用分治法。
这样就得到了矩阵的{1,1,1,0}的n-1次方的值。
下面是2个矩阵相乘的公式:
代码
public class Problem19 {
// 2×2的矩阵
class Matrix2X2 {
// 第一排第一个位置
int pos00;
// 第一排第二个位置
int pos01;
// 第二排第一个位置
int pos10;
// 第二排第二个位置
int pos11;
public Matrix2X2() {
}
public Matrix2X2(int pos00, int pos01, int pos10, int pos11) {
this.pos00 = pos00;
this.pos01 = pos01;
this.pos10 = pos10;
this.pos11 = pos11;
}
}
// 2个2×2的矩阵相乘得到新的矩阵
class MatrixMultiply {
public Matrix2X2 multiply(Matrix2X2 m1, Matrix2X2 m2) {
return new Matrix2X2(m1.pos00 * m2.pos00 + m1.pos01 * m2.pos10,
m1.pos00 * m2.pos01 + m1.pos01 * m2.pos11, m1.pos10
* m2.pos00 + m1.pos11 * m2.pos10, m1.pos10
* m2.pos01 + m1.pos11 * m2.pos11);
}
}
MatrixMultiply multiplyer = new MatrixMultiply();
// 求Fibonacci数第N个数
public Matrix2X2 getFibo(int n) {
if (n < 0) {
return null;
}
Matrix2X2 matrix22 = null;
if (n == 1) {
matrix22 = new Matrix2X2(1, 1, 1, 0);
}
// 偶数
else if (n % 2 == 0) {
matrix22 = getFibo(n / 2);
matrix22 = multiplyer.multiply(matrix22, matrix22);
}
// 奇数
else if (n % 2 != 0) {
//提取出第一个矩阵,生下来的矩阵就是偶数个,但是要记住在最后要把提取的第一个矩阵算上。
matrix22 = getFibo((n - 1) / 2);
matrix22 = multiplyer.multiply(matrix22, matrix22);
matrix22 = multiplyer.multiply(matrix22, new Matrix2X2(1, 1, 1, 0));
}
return matrix22;
}
//原始的递归法
public static int getFibo2(int n){
{
if (n==0||n==1)
{
return n;
}
else
{
return getFibo2(n-1)+getFibo2(n-2);
}
}
}
public static void main(String[] args) {
int n = 30;
Matrix2X2 matrix = new Problem19().getFibo(n - 1);
int fn = matrix.pos00;
System.out.println(fn);
int fn2 = Problem19.getFibo2(n);
System.out.println(fn2);
}
}
输出
832040
832040
扩展
有网友说可以通过下面的通项公式一步求解
Fibonacci通项公式:
an=1/√[(1+√5/2) n-(1-√5/2) n]