具体而言,为什么这个二进制Fibonacci算法具有指数运行时复杂性?

时间:2017-09-30 21:15:49

标签: algorithm

以下是我将参考的PDF: https://www.docdroid.net/htE62SR/215-216.pdf

我所指的算法(也可以在上面的PDF文件中找到)如下:

public static long fibonacciBad(int n) {
    if(n <= 1)
        return n;
    else
        return fibonacciBad(n-2) + fibonacciBad(n-1);
}

我试图理解为什么fibonacciBad是O(2 ^(n / 2)),假设我是正确的,因为PDF是暗示的。

我怀疑它与在A中的每一秒呼叫使用B有关,但具体情况我不清楚。此外,有人可以给我一个直观的解释,为什么它可以成为每一秒的呼叫,以便被认为是指数(而不是每一个呼叫数至少是前一个的两倍)? (我正在编写这个按字母顺序表示的符号,A和B,用于下面。这个符号不会在链接到这里的PDF中使用。)

A: 
c_0 = 1 
c_1 = 1 
c_2 = 1 + c_0 + c_1 = 1 + 1 + 1 = 3 
c_3 = 1 + c_1 + c_2 = 1+ 1 + 3 = 5 
c_4 = 1 + c_2 + c_3 = 1 + 3 + 5 = 9 
c_5 = 1 + c_3 + c_4 = 1 + 5 + 9 = 15 
c_6 = 1 + c_4 + c_5 = 1 + 9 + 15 = 25 
c_7 = 1+ c_5 + c_6 = 1 + 15 + 25 = 41 
c_8 = 1 + c_6 + c_7 = 1 + 25 + 41 = 67 

B: 
1 + 2 + 4 + ... + 2^(n-1) = 2^n - 1

2 个答案:

答案 0 :(得分:2)

你可以试着想象一下这个函数的计算方式:

                             fab(n)
                            /      \
                           /        \
                      fab(n-1)     fab(n-2)
                      /   \          /    \
                     /     \        /      \
               fab(n-2) fab(n-3) fab(n-3)  fab(n-4)
         ....    ....     ....      ... ...       ...   ...                 
           /    \      /     \      /     \         /    \ 
     fab(1) fab(1) fab(1) fab(1) fab(1) fab(1)  fab(1)  fab(1)

因此,这是一个高度为n的树,树中节点的总数为2^(n/2),因此计算的复杂性为O(2^n)

正如您所看到的,相同数量的计算重复次数相当多,因此您可以通过简单地将这些结果存储在缓存中来减少计算次数,从而获得O(n)的复杂性。

答案 1 :(得分:0)

由于计算中的重复,Fibonacci的朴素递归版本是指数式的:

你正在计算根:

F(n)取决于F(n-1)和F(n-2)

F(n-1)再次取决于F(n-2)和F(n-3)

F(n-2)再次取决于F(n-3)和F(n-4)

然后你在每个级别进行2次递归调用,这些调用在计算中浪费了大量数据,时间函数将如下所示:

T(n)= T(n-1)+ T(n-2)+ C,C常数

T(n-1)= T(n-2)+ T(n-3)> T(n-2)然后

T(n)> 2 * T(N-2)

...

T(n)> 2 ^(n / 2)* T(1)= O(2 ^(n / 2))

这只是一个下限,为了你的分析目的应该足够但实时函数是相同的Fibonacci公式,并且已知https://zingchart.github.io/zingtouch/是黄金比例的指数。

此外,您可以使用动态编程找到Fibonacci的优化版本,如下所示:

static int fib(int n)
{
    /* memory */
    int f[] = new int[n+1];
    int i;

    /* Init */
    f[0] = 0;
    f[1] = 1;

    /* Fill */
    for (i = 2; i <= n; i++)
    {
        f[i] = f[i-1] + f[i-2];
    }

    return f[n];
}

这是优化的,只做 n 步骤,但也是指数级的。

从输入大小到解决问题的步骤数定义成本函数。当您看到Fibonacci的动态版本( n 计算表格的步骤)或最简单的算法来了解数字是否为素数( sqrt(n)来分析有效除数的数量)。你可能认为这些算法是 O(n) O(sqrt(n)),但由于以下原因,这不是正确的: 算法的输入是一个数字: n ,使用二进制表示法,整数 n 的输入大小为 log2(n)然后执行

的变量
m = log2(n) // your real input size

让我们根据输入大小找出步数

m = log2(n)
2^m = 2^log2(n) = n

然后算法的成本与输入大小的函数是:

T(m) = n steps = 2^m steps

这就是成本是指数的原因。