Javascript阶乘函数记忆

时间:2019-04-05 15:26:59

标签: javascript performance factorial memoization

我正在尝试将阶乘函数与备忘录一起使用。我从对象中获取了最大值,以减少进行递归调用的次数。但是问题是第一次通话是我不知道这是否优化,因为第一次通话非常昂贵。任何对此的见识都将很棒。

let cache = {0: 1};
function factMemoize(key) {
    if (!cache[key]) {
        let maxVal = Object.keys(cache).reduce(function (a, b) {
            return Math.max(a, b);
        });
        console.log(maxVal);
        while (key >= maxVal) {
            cache[key] = key * factMemoize(key - 1);
            maxVal++;
        }
    }
    return cache[key];
}

2 个答案:

答案 0 :(得分:1)

正如该线程中提到的@ mark-meyer一样,将结果记忆起来并没有任何好处,因为每个值在计算过程中只会被计算一次。 Mark提供的解决方案非常适合通过调用具有相同或不同值的阶乘来在以后重新使用该功能。在这种情况下,您可以通过重用现有结果来加快流程并降低时间复杂度。

这是闭包中的样子:

function factorialFn() {
  const cache = [];

  return function _factorial() {
    if (n < 2) {
      return 1;
    }
    if (cache[n]) {
      return cache[n];
    }
    return cache[n] = n * _factorial(n - 1);
  }
}

然后,您可以像这样使用它:

const factorial = factorialFn();

factorial(5); // 120
factorial(7); // 5040


在第一次调用时,它将计算factorial(5)并将其保存在缓存中以备将来参考。

在第二个调用中,factorial(7)将执行7 * factorial(6)
其中factorial(6)基本上是6 * the cached value of factorial(5)

答案 1 :(得分:0)

由于只使用一次每个值,因此您从记住这一点上不会花很多钱。调用该函数后,您确实具有用于第二次调用的缓存,但是我们经常想到记忆是仅在函数期间存在的缓存中发生的某些事情。对于这样的事情,计算斐波那契数是一个典型的例子,其中记忆是对朴素递归函数的巨大改进。

话虽如此,在函数中尚不清楚为什么要使用对象作为缓存然后搜索它。您可以只使用其中索引将是您要计算的数字的数组。您无需搜索它,只需从数字开始并递归调用下一个较低的数字。如果有缓存,它将返回。例如:

let cache = [1];
function factMemoize(key) {
    if (!cache[key]) {
      cache[key] = key * factMemoize(key - 1)
    } else { // just to demo cache:
        console.log("cache hit:", key)
    }
    return cache[key]
}

// only hits cache at the end 
console.log("6! = ", factMemoize(6))

// second call benefits from cache:
console.log("8! = ", factMemoize(8))