package july37;
/**题目:O(logn)时间复杂度求Fibonacci数列
*
* O(logn)时间复杂度求Fibonacci数列
*
*
* 下面介绍一种时间复杂度是O(logn)的方法。在介绍这种方法之前,先介绍一个数学公式:
*{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1
*(注:{f(n+1), f(n), f(n), f(n-1)}表示一个矩阵。在矩阵中第一行第一列是f(n+1),第一行第二列是f(n),第二行第一列是f(n),第二行第二列是f(n-1)。)
*有了这个公式,要求得f(n),我们只需要求得矩阵{1, 1, 1,0}的n-1次方,因为矩阵{1, 1, 1,0}的n-1次方的结果的第一行第一列就是f(n)。这个数学公式用数学归纳法不难证明。感兴趣的朋友不妨自己证明一下。
*现在的问题转换为求矩阵{1, 1, 1, 0}的乘方。如果简单第从0开始循环,n次方将需要n次运算,并不比前面的方法要快。但我们可以考虑乘方的如下性质:
* / an/2*an/2 n为偶数时
*an=
* \ a(n-1)/2*a(n-1)/2*a1 n为奇数时
*要求得n次方,我们先求得n/2次方,再把n/2的结果平方一下。如果把求n次方的问题看成一个大问题,把求n/2看成一个较小的问题。这种把大问题分解成一个或多个小问题的思路我们称之为分治法。这样求n次方就只需要logn次运算了。
*实现这种方式时,首先需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算。当这些运算定义好了之后,剩下的事情就变得非常简单。完整的实现代码如下所示。
* @author 牵手无奈
*
*/
public class Fibonacci_logN {
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=1;i<10;i++){
System.out.println(fibonacci_logN(i)[0][1]);
}
}
/**求第n个fibonacci数
* @param n
* @return
*/
public static int[][] fibonacci_logN(int n){
if(n<=1){
return new int[][]{{1,1},{1,0}};
}else if((n&1)==0){
int[][] temp = fibonacci_logN(n/2);
temp = calMatrix(temp, temp);
return temp;
}else {
int[][] temp = fibonacci_logN(n/2);
temp = calMatrix(temp, temp);
temp = calMatrix(temp, new int[][]{{1,1},{1,0}});
return temp;
}
}
/**计算两个2*2的矩阵
* @param matrix1
* @param matrix2
* @return
*/
public static int[][] calMatrix(int[][] matrix1,int[][] matrix2){
int[][] result = new int[2][2];
result[0][0]=matrix1[0][0]*matrix2[0][0] + matrix1[0][1]*matrix2[1][0];
result[0][1]=matrix1[0][0]*matrix2[0][1] + matrix1[0][1]*matrix2[1][1];
result[1][0]=matrix1[1][0]*matrix2[0][0] + matrix1[1][1]*matrix2[1][0];
result[1][1]=matrix1[1][0]*matrix2[0][1] + matrix1[1][1]*matrix2[1][0];
return result;
}
}
O(logn)时间复杂度求Fibonacci数列(java)
最新推荐文章于 2022-03-05 13:39:34 发布