var lookup = {};
function memoized(n) {
if(n <= 1) { return 1; }
if(lookup[n]) {
return lookup[n];
}
lookup[n] = n * memoized(n - 1);
return lookup[n];
}
VS
function fact(n) {
if(n <= 1) { return 1; }
return n * fact(n-1);
}
如果我们称之为事实(3)
使用我们得到的第二种方法 - &gt; 3 *(2 *(1))
将结果存储在哈希中的效率增益是多少。它仅用于后续调用相同的函数吗?如果你只调用一次函数,我看不出你会得到什么。
使用memoized Fibonacci函数,即使只有一个函数调用,仍然可以提高效率。为了获得第n个斐波纳契数,如果你没有记忆,你将重复计算每个fib(n)上的fib(n-1)和fib(n-2)。我没有看到在阶乘函数中发生这种情况。
答案 0 :(得分:6)
实际上,使用它一次就没有效率。只有多次使用此方法才能获得效率
答案 1 :(得分:5)
因为您要将先前计算的阶乘的结果存储在lookup
中。
所以让我们说如果有另一个n=5
阶乘的调用,它已经计算出它只会返回lookup[5]
,所以不需要进一步的递归调用来计算该数字的阶乘。
因此,如果要提供许多请求,它会更强高效。
答案 2 :(得分:0)
当函数多次调用自身时,记忆功能将用于一次性函数调用。基本上可以分为几个递归路径。
以斐波那契为例。由于它将包含类似return fib(n - 1) + fib(n - 2)
的内容,因此在其周围传递已存储的值非常有意义,以便一个分支可以重用另一个分支的结果。
Factorial是直接的自顶向下算法,因此除非像示例中那样将已记忆的版本存储在函数本身之外,否则一次调用将不会获得任何好处。
对于像fibonacci这样的“分支”算法,您可以在已记忆的结构周围使用闭包,以使外部完全看不到它。您只需要为此功能即可。 在Scala中:
def fib(n: Int): Int = {
val memo = new mutable.HashMap[Int, Int]()
def fibRec(n: Int, memo: mutable.HashMap[Int, Int]): Int =
if (n < 2) {
memo(n) = n
n
} else {
memo(n) = fibRec(n - 1, memo) + fibRec(n - 2, memo)
memo(n)
}
fibRec(n, memo)
}
答案 3 :(得分:0)
没错!我也没有看到阶乘代码中的记忆化有任何好处,因为我们不会再次调用任何函数。
例如。
fact(5) -> 5 * fact(4) -> 4 * fact(3) -> 3 * fact(2) -> 2* fact(1)
在阶乘程序中永远不会发生冗余调用。所以阶乘代码中不需要记忆。
答案 4 :(得分:0)
只是想增强No Idea For Name的答案。正如前面提到的,这里使用记忆来重复使用先前执行的结果。
我从以下视频中截取了屏幕截图,它很好地解释了如何使用 Memoized Factorial。
Memoized Factorial:JS 代码执行的可视化 - YouTube
https://www.youtube.com/watch?v=js9160AAKTk