Memoize
MediumUpdated: Aug 2, 2025
Practice on:
Problem
Given a function fn, return a memoized version of that function.
A **memoized **function is a function that will never be called twice with the same inputs. Instead it will return a cached value.
You can assume there are 3 possible input functions: sum,fib,
and factorial.
sum** ** accepts two integersaandband returnsa + b. Assume that if a value has already been cached for the arguments(b, a)wherea != b, it cannot be used for the arguments(a, b). For example, if the arguments are(3, 2)and(2, 3), two separate calls should be made.fib** ** accepts a single integernand returns1ifn <= 1orfib(n - 1) + fib(n - 2)otherwise.factorialaccepts a single integernand returns1ifn <= 1orfactorial(n - 1) * notherwise.
Examples
Example 1
Input:
fnName = "sum"
actions = ["call","call","getCallCount","call","getCallCount"]
values = [[2,2],[2,2],[],[1,2],[]]
Output: [4,4,1,3,2]
Explanation:
const sum = (a, b) => a + b;
const memoizedSum = memoize(sum);
memoizedSum(2, 2); // "call" - returns 4. sum() was called as (2, 2) was not seen before.
memoizedSum(2, 2); // "call" - returns 4. However sum() was not called because the same inputs were seen before.
// "getCallCount" - total call count: 1
memoizedSum(1, 2); // "call" - returns 3. sum() was called as (1, 2) was not seen before.
// "getCallCount" - total call count: 2
Example 2
Input: fnName = "factorial"
actions = ["call","call","call","getCallCount","call","getCallCount"]
values = [[2],[3],[2],[],[3],[]]
Output: [2,6,2,2,6,2]
Explanation:
const factorial = (n) => (n <= 1) ? 1 : (n * factorial(n - 1));
const memoFactorial = memoize(factorial);
memoFactorial(2); // "call" - returns 2.
memoFactorial(3); // "call" - returns 6.
memoFactorial(2); // "call" - returns 2. However factorial was not called because 2 was seen before.
// "getCallCount" - total call count: 2
memoFactorial(3); // "call" - returns 6. However factorial was not called because 3 was seen before.
// "getCallCount" - total call count: 2
Example 3
Input: fnName = "fib"
actions = ["call","getCallCount"]
values = [[5],[]]
Output: [8,1]
Explanation: fib(5) = 8 // "call"
// "getCallCount" - total call count: 1
Constraints
0 <= a, b <= 10^51 <= n <= 101 <= actions.length <= 10^5actions.length === values.lengthactions[i]is one of "call" and "getCallCount"fnNameis one of "sum", "factorial" and "fib"
Solution
Method 1 – Closure with Argument Serialization
Intuition
To memoize a function, we need to cache results for each unique set of arguments. For JavaScript, we can use a Map to store results, using a stringified version of the arguments as the key. This ensures that each argument combination is cached separately, and repeated calls with the same arguments return the cached result.
Approach
- Create a cache (Map) to store results.
- For each call, serialize the arguments (e.g., using JSON.stringify).
- If the cache contains the key, return the cached value.
- Otherwise, call the original function, store the result in the cache, and return it.
- Track the number of times the original function is called (for getCallCount).
Code
JavaScript
function memoize(fn) {
const cache = new Map();
let callCount = 0;
const memoized = (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
callCount++;
const res = fn(...args);
cache.set(key, res);
return res;
};
memoized.getCallCount = () => callCount;
return memoized;
}
TypeScript
function memoize<T extends (...args: any[]) => any>(fn: T): T & { getCallCount: () => number } {
const cache = new Map<string, ReturnType<T>>();
let callCount = 0;
const memoized = (...args: Parameters<T>): ReturnType<T> => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key)!;
callCount++;
const res = fn(...args);
cache.set(key, res);
return res;
};
(memoized as any).getCallCount = () => callCount;
return memoized as T & { getCallCount: () => number };
}
Complexity
- ⏰ Time complexity:
O(1)for cache lookup and insert (amortized). - 🧺 Space complexity:
O(n), wherenis the number of unique argument sets cached.