Created
February 9, 2020 22:14
-
-
Save RP-3/c1035671ce6a78936452fa659b716d63 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 'Pure' recursive | |
// Note that this is almost literally just writing out the question statement | |
var uniquePaths = function(m, n) { | |
// also note this is a pure function: No side effects. No enclosed local vars | |
// Using an inner function just to keep things tidy and not pass (m, n) everywhere | |
const traverse = (i, j) => { // i, j are position on board | |
if(i === m-1 && j === n-1) return 1; // Count the number of ways the robot gets here. | |
// I.e., every time the robot gets here, return 1. | |
if(i >= m) return 0; // we are too far right. This is not a valid solution. Return 0. | |
if(j >= n) return 0; // we are too far down. This is not a valid solution either. Return 0. | |
// The robot can only move down and right. | |
return memo = traverse(i+1, j) // So try moving right | |
+ traverse(i, j+1); // And try moving down | |
}; | |
return traverse(0, 0); // The robot starts at 0, 0 | |
}; | |
// Memoized recursive | |
// Literally add two lines and edit the returns. | |
// 1. Init a memo table | |
// 2. Check the memo table | |
// 3. Memoize return statements | |
var uniquePaths = function(m, n) { | |
const memo = new Array(m).fill(0).map(() => new Array(n).fill(null)); // 1. init memo table | |
const traverse = (i, j) => { | |
if(i === m-1 && j === n-1) return 1; | |
if(i >= m) return 0; | |
if(j >= n) return 0; | |
if(memo[i][j] !== null) return memo[i][j]; // 2. Check memo table | |
return memo[i][j] = traverse(i+1, j) + traverse(i, j+1); // Memoize return statement | |
}; | |
return traverse(0, 0); | |
}; | |
/* | |
Now console.log the memo table by changing line 41 to: | |
const result = traverse(0, 0); // save the solution | |
console.log(memo); // <---- this is the only real change | |
return result; | |
Logs the following for m=3, n=2. | |
Should look suspiciously familiar! | |
[ | |
[ 3, 1 ], | |
[ 2, 1 ], | |
[ 1, null ] | |
] | |
Note that memo[i][j] === memo[i-1][j] + memo[i][j-1]. | |
Isn't that your DP relationship? | |
Look again at your recurrence relationship... | |
return memo[i][j] = traverse(i+1, j) + traverse(i, j+1); | |
That's exactly what your 'DP' solution does. | |
So the advantages of getting a 'pure' recursive solution are that: | |
1. Sometimes it's easier | |
2. Your optimized 'DP' solution literally falls out at your feet | |
3. Your recursive solution won't *necessarily* explore the entire memo table. | |
The disadvantages of going recursive are: | |
1. Call stacks are lame | |
2. Sometimes it's harder | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment