求解Fibonacci数列

  • 定义

斐波那契(Fibonacci)数列,在形式上可表示为从0开始的一个正整数序列:

0,\;1,\;1,\;2,\;3,\;5,\;8,\;13,\;21,\;34,\;55,\;89,\;144,\; \ldots\;

 

更正式一点的定义为:(摘自Cousera)

 

 

对于更深层次的探讨参见 维基百科:Fibonacci number

  •  

    求解1:递归

看到Fibonacci的定义,最直观的解法是使用递归:

 

import java.math.BigInteger;

public class Fibonacci1 {
	public static void main(String[] args) {
		//求解当n=40时的Fibonacci数
                int n = 40;
		
                //输出为BigInteger类型
                BigInteger result = null;
		
		long start = System.currentTimeMillis();
		
                //求解Fibonacci
		result = fib(n);
		
		long end = System.currentTimeMillis();
		System.out.println(String.format("RESUL::[%s], COST::[%s]ms", result, (end - start)));
	}
	
	private static BigInteger fib(int i) {
		if (i == 0)
			return BigInteger.valueOf(0);
		
		if (i == 1)
			return BigInteger.valueOf(1); 
		return fib(i - 1).add(fib(i - 2));
	}
	
}
 

 

  • 首先我们来验证算法的正确性

按照维基百科上给出的前20项表格:

 

F0F1F2F3F4F5F6F7F8F9F10F11F12F13F14F15F16F17F18F19F20
011235813213455891442333776109871597258441816765
 

给出验证代码:

 

package com.leetcode.problems;

import java.math.BigInteger;

public class Fibonacci1 {
	public static void main(String[] args) {
		for (int i = 0; i <= 20; i++)
			System.out.print(String.format("%s   ", fib(i)));
	}
	
	private static BigInteger fib(int n) {
		if (n == 0)
			return BigInteger.valueOf(0);
		
		if (n == 1)
			return BigInteger.valueOf(1); 
		return fib(n - 1).add(fib(n - 2));
	}
	
}
 

 

 

至此,可以断定算法是正确的。

 

  • 然后再来看看它的效率

当给定输入为 n = 35  时:

 

输出为9227465,用时 0.395

 

当给定输入为 n = 40 时,我们来看看测试结果:

 

输出为102334155,用时 3.149

 

当给定输入为 n = 50 时。。。计算的时间已经超出可接受的范围了。。。

可见这种直观的解法效率是极低的。

 

原因在于:当计算 n - 1 与 n - 2 时,它将分裂成两个分支:

即 n - 1 分裂为 n - 2,n - 3,而 n - 2 分裂为 n - 3,n - 4。不难看出,这里 n - 2,n - 3 被计算了两次。

 

 

  • 求解2:缓存计算过的下标 n 所对应的Fibonacci数

根据上面的例子,不难想到,我们何不将每一次递归所遇到的重复计算都缓存起来,这样下次再遇到这个下标 n 时就不用重复计算了。

这里我们缓存前两次计算过的Fibonacci数 n-1 和 n-2,并将递归改为循环,代码如下:

 

    private static BigInteger fastFib(int n) {
        BigInteger zero = BigInteger.valueOf(0L);
        if (n == 0)
            return zero;

        BigInteger one = BigInteger.valueOf(1L);
        if (n == 1)
            return one;

        BigInteger _2 = zero;
        BigInteger _1 = one;

        for (int i = 2; i <= n; i++) {
            BigInteger current = _2.add(_1);
            _2 = _1;
            _1 = current;
        }

        return _1;
    }
 

 

alright。。。大早晨的睡不着起来写了这篇博客,算是醒脑了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值