Big O表示法 - O(N)Fibonacci生成器

时间:2018-03-25 11:13:12

标签: big-o fibonacci memoization

在面试之前刷新我的大O.

在破解编码访谈(第6版)的第53和54页上,在关于大O的章节中,您将看到示例15,如下所示。

void allFib(int n){
    int[] memo = new int[n+1];
    for(int i=0; i<n; i++){
        System.out.println(i + ":" + fib(i,memo));
    }
}

int fib(int n, int[] memo){
    if(n<=0) return 0;
    else if(n==1) return 1;
    else if(memo[n]>0) return memo[n];

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

    return memo[n];
}

长话短说,这是一种标准方法,它使用记忆来确保只需计算一次fib值。但是它们仍然需要计算一次并且计算它们是O(2 ^ N)时间复杂度。

这本书说的是因为我们可以从算法为O(N)的备忘录中以恒定时间检索fib值。

它没有解释为什么我们可以忽略这样一个事实,即你必须从指数函数中获取一次值。是否适用摊销?

我相信这本书,但所提供的解释并没有帮助我理解为什么在这种情况下时间复杂度为O(N)。

发布编辑:

让我换一种说法。

如何调用fib n次为O(N)......     int [] memo = new int [n + 1];

for(int i=0; i<n; i++){
    System.out.println(i + ":" + fib(i,memo));
}

......一次调用它是O(N ^ 2)?

fib(n,memo)

最终编辑: 谢谢大家。我有我的答案。即使是对fib方法的单次调用也会从memoisation中获益,因此不是O(N ^ 2),它也是O(N)。

2 个答案:

答案 0 :(得分:1)

查看此问题的一种方法是memo[n]=fib(n-1,memo)+fib(n-2,memo)fib(n-1, memo)返回时,fib(n-2,memo)所需的值已存储在memoif(memo[n]>0) return memo[n])中,这会在每个递归级别重复。

所以代替看起来像这样的调用图(对于天真的版本):

        *
       * *
      * * * * 
  * * * * * * * *

看起来像这样

         *
        * * 
       * *   
      * *  

答案 1 :(得分:0)

它是O(N),因为您只计算一次每个值并稍后重复使用计算值。例如。对于fib(4),这将是调用堆栈:

fib(4) = fib(3) + fib(2);
    fib(3) = fib(2) + fib(1);
        fib(2) = fib(1) + fib(0); // value stored
            fib(1) = 1;
            fib(0) = 1;
    fib(2) = 2; // value accessed

存储的值在已经计算时被访问。

当你看一下Fibonacci数字的“懒惰实现”时:

int fib(int i) {
    if(i <= 1) return 1;
    return fib(i - 1) + fib(i - 2);
}

您需要多次计算很多数字。例如。再次为fib(4)调用堆栈看起来像:

fib(4) = fib(3) + fib(2);
    fib(3) = fib(2) + fib(1);
        fib(2) = fib(1) + fib(0);
            fib(1) = 1;
            fib(0) = 1;
    fib(2) = fib(1) + fib(0);
        fib(1) = 1;
        fib(0) = 1;

如您所见,fib(2)fib(1)fib(0)需要多次计算。使用记忆方法,您只需计算一次新值。此外,请记住,调用堆栈随着Fibonacci值的增加而呈指数级增大,从而导致更多的“双重计算”数字。这就是为什么这种懒惰的方法有O(2^N)而内存方法是O(N)

HTH