记忆斐波那契的时间复杂性?

时间:2017-03-06 03:52:44

标签: javascript runtime time-complexity big-o fibonacci

我有memoization fibonacci代码,我无法弄清楚它的时间复杂性:

function fibMemo(index, cache) {
  cache = cache || [];
  if (cache[index]) return cache[index];
  else {
    if (index < 3) return 1;
    else {
      cache[index] = fibMemo(index - 1, cache) + fibMemo(index - 2, cache);
    }
  }

  return cache[index];
}

这个功能的时间复杂度是多少?

3 个答案:

答案 0 :(得分:9)

取决于你的意思。

假设记忆正确完成了&#34;操作&#34;将是生成的数字的数量。这意味着函数运行时会相对于您尝试生成的数字量而增长。

所以它是O(n),其中n是生成的数字的数量。

答案 1 :(得分:1)

假设T(n)是n的时间复杂度,所以T(n) = T(n-1) + T(n-2)。因为在计算F(n-2)cacheF(n - 1)中,所以F(n-2)的运算为1(从cache读取),因此T(n) = T(n-1) + 1 = T(n-2) + 2 = ... = T(n-n) + nT(0)是1,所以T(n) = O(n + 1) = O(n)

答案 2 :(得分:0)

无备忘录

我认为当您使用记忆时,在您的脑海中清楚一幅呼叫树的样子会很有帮助。例如,fib(5)的外观如下:

enter image description here

此算法的时间复杂度是多少?好吧,我们叫fib()多少次?要回答这个问题,请考虑树的每个级别。

第一级有一个呼叫:fib(5)。下一级别有两个调用:fib(4)fib(3)。下一级有四个。等等等等。每个节点都分支为另外两个节点,因此为2*2*2... = 2^n。好吧,它是O(2^n),通常不是完全2^n。您可以看到,这里的第4级缺少一个节点,而第5级只有一个节点。

带有备忘录

现在考虑备忘录的外观。使用备忘录时,您会记住以前计算的结果。所以看起来像这样:

enter image description here

那些带有正方形的对象只是返回记录的结果。如果您忽略它们,则可以看到该算法只是针对0n中的每个值被调用一次。

好吧,fib(1)确实被称为“额外”一次,但是由于我们在这里考虑big-O,所以它不会改变任何事情。与周围带有正方形的调用相同。即使我们希望包括它们,也​​仍然是O(n)

要向自己证明这一点并使其直观,请尝试为大于fib(5)的内容写出一个调用树。可能是fib(10)fib(20)。您会看到,如果您起眼睛,那基本上就是对角线向下和向左移动的形式。可能到处都有一些额外的分支萌芽,但基本上是一条线。