6
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);
}

If we call fact(3)

With the second method we get --> 3 * (2 * (1))

What is the efficiency gain of storing the result in a hash. Is it only for subsequent calls to the same function? I can't see how you would gain anything if you are only calling the function once.

With the memoized Fibonacci function, even if there is only one function call there is still an efficiency gain. To get the nth fibonacci number, if you do not memoize, you will be repeating the calculation for fib(n-1) and fib(n-2) on each fib(n). I don't see this happening in the factorial function.

ordinary
  • 5,943
  • 14
  • 43
  • 60
  • You don't call the function once. The function calls itself many times. – Blender Jul 28 '13 at 06:54
  • 2
    What I meant was you initially call it once. And even though the function calls itself many times, how does storing the result of each call in a hash save any time. Because for fact(4), fact(3) is only called once, as is fact(2) and fact(1). At that point the values will pop back up the stack and give u the end result of fact(4). I don't see how memoization fits in. – ordinary Jul 28 '13 at 06:57
  • 1
    @ordinary you should accept one of the answers or write your own answer to the question – No Idea For Name Sep 02 '13 at 06:34
  • It's actually a time loss (time to store values in the table and checking if it exists in the lookup table) for the first call. It gains time for subsequent calls. – TheRandomGuy May 27 '16 at 07:57

5 Answers5

10

actually there is no efficiency gained by using it once. you gain efficiency only if this method is used several times

No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
  • ...and even then, whatever you store the memoized results in needs to exist outside of the scope of the factorial function itself, otherwise you start over each time the function is called and there is zero benefit – jrnxf Dec 15 '19 at 01:33
  • @jrnxf Well, not really: it can be a function-static dictionary, in which case it's declared within the function but persists between calls. – underscore_d Jan 27 '23 at 21:05
4

Because you are storing the result of previously calculated factorials in lookup.

so let's say if there is another call for factorial of n=5 which already calculated it'll just return lookup[5] so no further recursive calls will be required for calculating that number's factorial.

And hence it'll more efficient if it is going to serve many requests.

VishalDevgire
  • 4,232
  • 10
  • 33
  • 59
  • 3
    So it is for subsequent calls then? There is no gain to be had on the first call. In fact probably a slight (negligible) cost because you are storing the values in a hash on each call – ordinary Jul 28 '13 at 07:00
  • 1
    Exactly no gain on the first call but if this code is going to stay longer for calculating factorials, it'll be lot more effecient than it's other counter part. – VishalDevgire Jul 28 '13 at 07:01
1

Memoization would work for one-off functional call when the function calls itself multiple times. Basically branching into several recursive paths.

Take fibonacci for example. Since it will contain something like return fib(n - 1) + fib(n - 2) it would make a lot of sense to pass memoized values around so that one branch can reuse the other's results.

Factorial is a direct top-down algorithm, so it's not going to gain anything for one-off call unless, like in the example, the memoized version is stored outside the function itself.

For "branched" algorithms like fibonacci, you can use closure around a memoized structure so that it is not visible to the outside at all. You just need to functions for it. In 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)
}
yuranos
  • 8,799
  • 9
  • 56
  • 65
1

Just want to enhance of answer of No Idea For Name. As it was mentioned, memoization used here to re-use results from a previous execution.

I take the screen shot from following video, and it explains great how you can use Memoized Factorial.

Memoized Factorial: Visualization of JS code execution - YouTube
https://www.youtube.com/watch?v=js9160AAKTk

enter image description here

Teoman shipahi
  • 47,454
  • 15
  • 134
  • 158
-1

Exactly! I also don't see any benefit of memoization in factorial code as we are not going to call any of the functions again.

For eg.

fact(5) -> 5 * fact(4) -> 4 * fact(3) -> 3 * fact(2) -> 2* fact(1)

No Redundant call is going to happen in the factorial program ever. So Memoization is not needed in factorial code.