【问题标题】:Fibonacci Series using Dynamic Programming使用动态规划的斐波那契数列
【发布时间】:2016-06-17 05:20:50
【问题描述】:

让我们考虑使用动态规划来实现斐波那契数列。

// Fibonacci Series using Dynamic Programming
class fibonacci
{
static int fib(int n)
{
    /* Declare an array to store Fibonacci numbers. */
int f[] = new int[n+1];
int i;

/* 0th and 1st number of the series are 0 and 1*/
f[0] = 0;
f[1] = 1;

for (i = 2; i <= n; i++)
{
   /* Add the previous 2 numbers in the series
     and store it */
    f[i] = f[i-1] + f[i-2];
}

return f[n];
}

public static void main (String args[])
{
    int n = 9;
    System.out.println(fib(n));
}
} 

我们使用动态规划使得递归工作的重复不会发生。但是这里每次调用该函数时,都会生成一个新数组。那么如何说这个算法更优化呢?

【问题讨论】:

  • 每次? .我猜每个函数调用都会创建一次数组。假设你想找到第 100 个斐波那契数。所以一个 100 的数组只会被创建一次来存储数字。
  • 如果不想每次调用fib时都创建数组,就不要在fib中创建。
  • 另外,添加递归的也会占用 O(n) 空间,因为它会创建一棵树。
  • 这是来自 GeeksForGeeks 的解决方案。观察代码的第 6 行。每次为每个单独的函数调用创建一个新数组时
  • “更优化”比什么?这个问题要么是另一个“请写一个高效的 Fib 版本”,要么是要求将使用 O(n) 存储的 Fibonacci 版本与未指定的算法进行比较。

标签: algorithm dynamic-programming


【解决方案1】:

一项优化将仅保存最后 2 个值,而不是所有结果。您不需要存储所有结果。

您也可以在 O(n) 中递归地编写斐波那契数列:

int fib(int n1, int n2, int counter)
{
    if(counter == 0)
    {
        return n2;
    }
    else
    {
        return fib(n2,n2 + n1,counter-1);
    }
}

//to start:
int result = fib(0,1,100); //gives you the 100 fibonacci value

此代码递归运行,易于阅读。您不必初始化数组或其他东西。

您也可以使用非递归选项:

int fib(int number)
{
    int n1 = 0;
    int n2 = 1;
    int temp;
    for(int i = 0; i< number;i++)
    {
        temp = n1 + n2;
        n1 = n2;
        n2 = temp;
    }
    return n2;
}

如果要存储结果,则必须在 fib 函数之外初始化数组:

// Fibonacci Series using Dynamic Programming
class fibonacci
{
    /* Declare an array to store Fibonacci numbers. */
    int f[];

    static void init(int n)
    {    /* 0th and 1st number of the series are 0 and 1*/
        f = new int[n+1];            
        f[0] = 0;
        f[1] = 1;
    }

    static int fib(int n)
    {
        int i;

        for (i = 2; i <= n; i++)
        {
           /* Add the previous 2 numbers in the series
             and store it */
            f[i] = f[i-1] + f[i-2];
        }

        return f[n];
    }

    public static void main (String args[])
    {
        int n = 9;
        init(n);
        System.out.println(fib(n));
    }
} 

【讨论】:

  • 将结果保存到数组中才有意义,如果您以后使用它们
  • 这回答了“我如何编写 O(n) 整数算术运算,O(1) 附加整数存储斐波那契函数”的问题,但我认为这不是问题所在。
  • 你是对的......因此我编辑了我的答案 thx @PaulHankin
【解决方案2】:

我们使用记忆化来防止动态编程的进一步递归。记忆化是存储已经计算的值的方式——假设索引 m 的 fib(m) 被计算并存储在记忆化表中。在接下来的递归中,如果 fib(m) 再次出现以进行计算,那么我们从记忆表中获取它而不是再次执行 fib(m-1)+fib(m-2) 即避免不必要的递归......注意 - 这将保持复杂度线性,即 O(n)。

我们可以通过多种方式实现这种记忆化,以加快搜索速度。然而,对于斐波那契,我们可以将记忆化实现为数组。 是的,记忆表只会被初始化一次。下面的代码是上述解释的说明-

注意 - 我们采用了一个变量“复杂度”,每当我们在记忆表中找不到值时,即当我们进行递归时,它都会增加。

package com.company.dynamicProgramming;

import java.math.BigInteger;

public class FibonacciByBigDecimal {


    static int complexity = 0;

    public static void main(String ...args) {

        int n = 200;
        BigInteger[] memoization = new BigInteger[n + 1];

        System.out.println("fibonacci of "+ n + " is : " + fibByDivCon(n, memoization));
        System.out.println("Complexity is "+complexity);

    }


    static BigInteger fibByDivCon(int n, BigInteger[] memoization){

        if(memoization[n]!=null){
            return memoization[n];
        }

        complexity++;      

        if (n == 1 || n== 2){
            memoization[n] = BigInteger.ONE;
            return BigInteger.ONE;
        }

        // creates 2 further entries in stack
        BigInteger fibOfn = fibByDivCon(n-1, memoization).add( fibByDivCon(n-2, memoization)) ;

        memoization[n] = fibOfn;

        return fibOfn;

    }

}

上面我正在计算索引 200 处的斐波那契数。当我运行上面的代码时,结果是:-

fibonacci of 200 is : 280571172992510140037611932413038677189525
Complexity is 200

Process finished with exit code 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    • 2020-07-16
    • 2016-08-07
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多