O(logn)时间复杂度求Fibonacci数列(java)

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;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值