【发布时间】:2016-09-12 08:26:48
【问题描述】:
我试图解释正确缓存的斐波那契算法复杂性。这是代码(https://jsfiddle.net/msthhbgy/2/):
function allFib(n) {
var memo = [];
for (var i = 0; i < n; i++) {
console.log(i + ":" + fib(i, memo))
}
}
function fib(n, memo) {
if (n < 0) return 0;
else if (n === 1) return 1;
else if (memo[n]) return memo[n];
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
allFib(5);
解决方案取自“Cracking the coding interview”并改编为javascript。 所以这是一个“不是很好”的函数调用树
我是这样想的:“最左边的分支(粗体)是进行评估的地方”,这绝对是第一次传递给 allFib 函数的数字。所以复杂度是O(n)。右侧的所有内容都将从缓存中获取,并且不需要额外的函数调用“。正确吗?以及如何将其连接到树“理论”。在这种情况下,树的深度和高度为 4,但是不是 5(接近 n 但不是它)。我希望答案不直观但更可靠。
【问题讨论】:
-
当涉及缓存时,f(k) 被评估多少次(对于任何 k)?
-
memo[n]未使用! -
是的,memo 未使用首先检查该值是否存在于 memo 中,如果不存在则只计算 fib() 并分配给 memo。 if(memo[n]){return memo[n]} else {memo[n] = fib(n - 1, memo) + fib(n - 2, memo);返回备忘录[n];}
-
好吧,
O(n)是计算未缓存/新值的复杂性。访问缓存的复杂度为O(1),因此该算法的最终复杂度必须介于O(1)和O(n)之间,具体取决于n和缓存的状态。 -
是的,可以。此时您的“问题”是缓存提供给功能,因此您永远不知道该缓存中有多少值;在
allFib的情况下,您总是从一个新的(空)缓存开始。但是您可以重用缓存,然后对 allFib() 的第二次调用将从缓存中“计算”出相同的 5 个值。因此,总共只计算了 5 次计算的 10 个值,其余的来自缓存。通常我会将缓存烘焙到 fib 函数中并避免这种怀疑。
标签: javascript algorithm memoization