我试图正确解释缓存的fibonacci算法复杂性。这是代码():
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);
解决方案取自&#34;破解编码面试&#34;并适应javascript。 所以这是一个不太好的&#34;函数树调用
https://jsfiddle.net/msthhbgy/2/
我这样想:&#34;最左边的分支(粗体)是评估发生的地方&#34;它绝对是第一次传递给allFib函数的数字。所以复杂性是O(n)。右边的所有内容都将从缓存中获取,不需要额外的函数调用&#34;。这是对的吗?还有如何将它连接到树&#34;理论&#34;。在这种情况下树的深度和高度是4但不是5(接近n但不是它)。我希望答案不直观但更可靠。
答案 0 :(得分:1)
首先,检查否定n
,并将值移至零。
然后检查值是否被缓存,取值。如果不是,请将值分配给缓存并返回结果。
针对n === 0
或n === 1
分配n
的特殊情况。
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = n === 0 || n === 1 ? n : f(n - 1) + f(n - 2);
}
var cache = [];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));
&#13;
部分使用cache
中的预定义值,建议使用Thomas。
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = f(n - 1) + f(n - 2);
}
var cache = [0, 1];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));
&#13;
答案 1 :(得分:1)
这是一个真正使用缓存的函数:
function Fibonacci() {
var memo = [0, 1];
this.callCount = 0;
this.calc = function(n) {
this.callCount++;
return n <= 0 ? 0
: memo[n] || (memo[n] = this.calc(n - 1) + this.calc(n - 2));
}
}
var fib = new Fibonacci();
console.log('15! = ', fib.calc(15));
console.log('calls made: ', fib.callCount);
fib.callCount = 0; // reset counter
console.log('5! = ', fib.calc(5));
console.log('calls made: ', fib.callCount);
fib.callCount = 0;
console.log('18! = ', fib.calc(18));
console.log('calls made: ', fib.callCount);
&#13;
进行的函数调用次数为:
(n - min(i,n))*2+1
i 是备忘录中的最后一项。
您可以通过 n = 18 和 i = 15 的示例看到以下内容:
按此顺序拨打电话:
calc(18)
calc(17) // this.calc(n-1) with n=18
calc(16) // this.calc(n-1) with n=17
calc(15) // this.calc(n-1) with n=16, this can be returned from memo
calc(14) // this.calc(n-2) with n=16, this can be returned from memo
calc(15) // this.calc(n-2) with n=17, this can be returned from memo
calc(16) // this.calc(n-2) with n=18, this can be returned from memo
一般模式是this.calc(n-1)
和this.calc(n-2)
被调用的次数(当然),此外还有原始调用calc(n)
。
以下是第一次将fib.calc
称为fib.calc(5)
时的动画。箭头显示所做的调用。向左越多,递归越深。当相应的结果存储在备忘录:
当 i 是给定的常数时,这显然是 O(n)。