对于具有递归的Fibonacci系列,这是一种更好的方法吗?

时间:2015-02-13 21:07:34

标签: java algorithm recursion

我在哪里看到Recursive Fibonacci系列每个人都告诉

a[i] = fib(i - 1) + fib( i - 2)

但它也可以用

解决
a[i] = fib(i - 1) + a[i-2] // If array 'a' is a global variable.

如果数组'a'是全局变量,则在计算[i-2]时会计算[i-2];

可以用java中的以下程序解决..

public class Fibonacci {

    public static int maxNumbers = 10;
    public static double[] arr = new double[maxNumbers];

    public static void main(String args[])
    {
        arr[0] = 0;
        arr[1] = 1;

        recur(maxNumbers - 1);
    }

    public static double recur(int i)
    {
        if( i > 1)
        {
            arr[i] = recur(i - 1) + arr[i - 2];
        }

        return arr[i];
    }
}

此外,与原始程序相比,复杂性也更低。这样做有什么不利之处吗?

5 个答案:

答案 0 :(得分:4)

你已经完成了Dynamic Programming计算Fibonacci的第一步,DP的想法是避免冗余计算,你的算法实现了它的目标。

“经典”自下而上的DP Fibonacci实现正在填充从低到高的元素:

arr[0] = 0
arr[1] = 1
for (int i = 2; i <= n; i++)
    arr[i] = arr[i-1] + arr[i-2]

(优化可以单独存储curr,last,并在每次迭代时修改它们。

原则上你的方法基本相同。


作为旁注,用于计算斐波那契的DP方法正在花费O(n)时间,其中存在更有效的矩阵指数解决方案:

1 1 
1 0

上述情况适用,因为您使用

这一事实
1     1               F_{n+1}                1*F{n+1} + 1*F{n}           F_{n+2}
               *                       =                          =                         
1     0               F_{n}                  1*F{n+1} + 0*F{n}           F_{n+1}

在上述矩阵中使用exponent by squaring,可以在O(logn)中解决此问题。

答案 1 :(得分:2)

如果你只想要第n个斐波纳契数,你可以这样做:

static double fib(double prev, double curr, int n) {

    if(n == 0)
        return curr;

    return fib(curr, prev+curr, n-1);

}

初始条件为prev = 0curr = 1n = maxNumbers。此函数是尾递归的,因为您不需要为任何其他计算存储递归调用的返回值。初始堆栈帧被重用(这节省了内存),一旦你遇到你的基本情况,返回的值与从每个其他递归调用返回的值相同。

答案 2 :(得分:1)

您也可以使用两个递归函数进行编码,但是同样的值会反复计算所以您可以执行动态编程方法,您可以存储该值并将其返回到需要的地方。就像在C ++中一样这样做

#include <bits/stdc++.h>

using namespace std;

int dp[100];

int fib(int n){

   if(n <= 1)
     return n;

   if(dp[n]!= -1)
     return dp[n];

   dp[n] = fib(n-1) + fib(n-2);

   return dp[n];

}

int main(){

   memset(dp,-1,sizeof(dp));

   for(int i=1 ;i<10 ;i++)
    cout<<fib(i)<<endl;

}

答案 3 :(得分:1)

通过使用类似于您的数组,您只需重新计算两个分支中的一个(每次迭代中最长的分支),最终会出现O(n)复杂度。

如果你要跟踪你之前已经解决过多大的斐波纳契数,你可以使用它并产生O(max(n-prevn,1))。以下是代码的更改版本,如果需要,可以从底部填充数组:

public class Fibonacci {
    public static final int maxNumbers = 93; // fib(93) > Long.MAX_VALUE 
    public static long[] arr = new long[maxNumbers];
    public static int calculatedN = 0;

    public static long fib(int i) throws Exception
    {
        if( i >= maxNumbers )
            throw new Exception("value out of bounds"); 

        if( calculatedN == 0 ) {
            arr[0] = 0L;
            arr[1] = 1L;
            calculatedN = 1;
        }

        if( i > calculatedN ) {
           for( int x=calculatedN+1; x<=i; x++ ){
             arr[x] = arr[x-2] + arr[x-1];
           }
           calculatedN = i;
        }

        return arr[i];
    }

    public static void main (String args[]) {
       try {
        System.out.println(fib(50)); // O(50-2)
        System.out.println(fib(30)); // O(1)        
        System.out.println(fib(92)); // O(92-50)
        System.out.println(fib(92)); // O(1)        
       } catch ( Exception e ) { e.printStackTrace(); }
    }
}

我改变了双倍长。如果你需要比fib(92)更大的斐波纳契数,我会从长变为Biginteger。

答案 4 :(得分:0)

这只是非递归版本的一步: https://gist.github.com/vividvilla/4641152

一般来说,这种部分递归的方法看起来非常混乱