|
| 1 | +# Memoize II |
| 2 | +[LeetCode Problem]https://leetcode.com/problems/memoize-ii/ |
| 3 | + |
| 4 | +Given a function fn, return a memoized version of that function. |
| 5 | + |
| 6 | +A memoized function is a function that will never be called twice with the same inputs. Instead it will return a cached value. |
| 7 | + |
| 8 | +fn can be any function and there are no constraints on what type of values it accepts. Inputs are considered identical if they are === to each other. |
| 9 | + |
| 10 | +## Example 1: |
| 11 | +```javascript |
| 12 | +Input: |
| 13 | +getInputs = () => [[2,2],[2,2],[1,2]] |
| 14 | +fn = function (a, b) { return a + b; } |
| 15 | +Output: [{"val":4,"calls":1},{"val":4,"calls":1},{"val":3,"calls":2}] |
| 16 | +Explanation: |
| 17 | +const inputs = getInputs(); |
| 18 | +const memoized = memoize(fn); |
| 19 | +for (const arr of inputs) { |
| 20 | + memoized(...arr); |
| 21 | +} |
| 22 | + |
| 23 | +For the inputs of (2, 2): 2 + 2 = 4, and it required a call to fn(). |
| 24 | +For the inputs of (2, 2): 2 + 2 = 4, but those inputs were seen before so no call to fn() was required. |
| 25 | +For the inputs of (1, 2): 1 + 2 = 3, and it required another call to fn() for a total of 2. |
| 26 | +``` |
| 27 | + |
| 28 | +## Example 2: |
| 29 | +```javascript |
| 30 | +Input: |
| 31 | +getInputs = () => [[{},{}],[{},{}],[{},{}]] |
| 32 | +fn = function (a, b) { return ({...a, ...b}); } |
| 33 | +Output: [{"val":{},"calls":1},{"val":{},"calls":2},{"val":{},"calls":3}] |
| 34 | +Explanation: |
| 35 | +Merging two empty objects will always result in an empty object. It may seem like there should only be 1 call to fn() because of cache-hits, however none of those objects are === to each other. |
| 36 | +``` |
| 37 | + |
| 38 | + |
| 39 | +## Example 3: |
| 40 | +```javascript |
| 41 | +Input: |
| 42 | +getInputs = () => { const o = {}; return [[o,o],[o,o],[o,o]]; } |
| 43 | +fn = function (a, b) { return ({...a, ...b}); } |
| 44 | +Output: [{"val":{},"calls":1},{"val":{},"calls":1},{"val":{},"calls":1}] |
| 45 | +Explanation: |
| 46 | +Merging two empty objects will always result in an empty object. The 2nd and 3rd third function calls result in a cache-hit. This is because every object passed in is identical. |
| 47 | +``` |
| 48 | + |
| 49 | +### Constraints: |
| 50 | +```javascript |
| 51 | +1 <= inputs.length <= 105 |
| 52 | +0 <= inputs.flat().length <= 105 |
| 53 | +inputs[i][j] != NaN |
| 54 | +``` |
| 55 | + |
| 56 | +## Approach: |
| 57 | +Map is perfect for storing single argument. Each consecutive argument must have cache based on previous argument, which will form a tree like structure, like this: |
| 58 | +```javascript |
| 59 | +fn(1,3,4) // { 1: { 3: { 4: {}}}}; |
| 60 | +fn(1,4,3) // { 1: { 3: { 4: {}}, 4: { 3: {}}}}; |
| 61 | +``` |
| 62 | +The only problem, is how do we store our result. It's been never stated, that memoized function will be called with the same amount of arguments every time. We need a way to store our result anywhere on the path and also make sure that it will never be misteaken with argument. Here is example. |
| 63 | +```javascript |
| 64 | +fn(1,3) // { 1: { 3: 4}}; |
| 65 | +-> 4 |
| 66 | +fn(1) // { 1: { 3: 4}}; |
| 67 | +-> { 3: 4 } // returning cache branch as result |
| 68 | +``` |
| 69 | +There are different aproaches to overcome this. But since every Symbol() call is guaranteed to return a unique Symbol we can use it to store actual result with guarantee, that it will never match any argument. |
| 70 | + |
| 71 | +## Problem Added By |
| 72 | + |
| 73 | +- [deveshidwivedi](https://github.com/deveshidwivedi) |
| 74 | + |
| 75 | + |
| 76 | + |
| 77 | +## Contributing |
| 78 | +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. |
| 79 | + |
| 80 | +Please make sure to update tests as appropriate. |
0 commit comments