如何记忆递归因子函数使其更有效率?

时间:2013-07-28 06:53:08

标签: recursion fibonacci memoization factorial

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)。我没有看到在阶乘函数中发生这种情况。

5 个答案:

答案 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

enter image description here

相关问题