Skip to content

Commit 329318d

Browse files
Memolization and tabulization
1 parent f519ee3 commit 329318d

10 files changed

+300
-133
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* 02:12:45 - https://youtu.be/oBt53YbR9Kk?t=7965
3+
*
4+
* Problem:
5+
* Write a function `canConstruct(target, wordBank)` that accepts a target and an array of strings.
6+
* The function should return a boolean indicating whether or not the `target` can be constructed
7+
* by concatenating elements of `wordBank` array.
8+
* You may reuse elements of `wordBank` as many times as needed.
9+
*/
10+
11+
/**
12+
* Brute Force Approach
13+
* This function attempts to solve the problem using recursion without any optimizations.
14+
* @param {string} target - The target string we want to construct.
15+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
16+
* @returns {boolean} - Returns true if the target can be constructed, otherwise false.
17+
*/
18+
function canConstruct(target, wordBank) {
19+
// Base case: If the target is an empty string, we can construct it by using zero words.
20+
if (target === '') {
21+
return true;
22+
}
23+
24+
// Iterate over each word in the wordBank
25+
for (const word of wordBank) {
26+
// Check if the word is a prefix of the target
27+
if (target.indexOf(word) === 0) {
28+
// If it is, we create a new target by removing the prefix (word)
29+
const suffix = target.slice(word.length);
30+
// Recursively check if we can construct the new target (suffix) with the wordBank
31+
if (canConstruct(suffix, wordBank)) {
32+
return true;
33+
}
34+
}
35+
}
36+
37+
// If no combination of words can construct the target, return false
38+
return false;
39+
}
40+
41+
console.log("===== Brute Force =====");
42+
43+
// Brute Force
44+
// m = target.length
45+
// n = wordBank.length
46+
// Time Complexity: O(n^m * m)
47+
// In the worst case, we have to explore all combinations of the wordBank for each character in the target.
48+
// Space Complexity: O(m^2)
49+
// Due to the call stack and slicing of strings.
50+
console.log(canConstruct('abcdef', ['ab', 'abc', 'cd', 'abcd'])); // true
51+
console.log(canConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // false
52+
console.log(canConstruct('enterapotentpot', ['a', 'p', 'ent', 'enter', 'ot', 'o', 't'])); // true
53+
console.log(canConstruct('eeeeeeeeeeeeeeeeeeeeeeeeeef', ['e', 'ee', 'eee', 'eeee', 'eeeee', 'eeeeee'])); // false
54+
55+
56+
/**
57+
* Optimized Approach using Memoization
58+
* This function optimizes the brute force approach by using memoization to store the results of subproblems.
59+
* @param {string} target - The target string we want to construct.
60+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
61+
* @param {object} memo - An object used to store the results of subproblems.
62+
* @returns {boolean} - Returns true if the target can be constructed, otherwise false.
63+
*/
64+
function optimizedCanConstruct(target, wordBank, memo = {}) {
65+
// Check if the result for the current target is already in the memo
66+
if (target in memo) return memo[target];
67+
// Base case: If the target is an empty string, we can construct it by using zero words.
68+
if (target === '') return true;
69+
70+
// Iterate over each word in the wordBank
71+
for (const word of wordBank) {
72+
// Check if the word is a prefix of the target
73+
if (target.indexOf(word) === 0) {
74+
// If it is, we create a new target by removing the prefix (word)
75+
const suffix = target.slice(word.length);
76+
// Recursively check if we can construct the new target (suffix) with the wordBank
77+
if (optimizedCanConstruct(suffix, wordBank, memo)) {
78+
// Store the result in the memo and return true
79+
memo[target] = true;
80+
return true;
81+
}
82+
}
83+
}
84+
85+
// Store the result in the memo and return false
86+
memo[target] = false;
87+
return false;
88+
}
89+
90+
console.log("===== Memoization =====");
91+
// Memoization
92+
// m = target.length
93+
// n = wordBank.length
94+
// Time Complexity: O(n * m^2)
95+
// For each character in the target (m), we iterate over the wordBank (n) and slice the string (m).
96+
// Space Complexity: O(m^2)
97+
// Due to the memo object and the call stack.
98+
console.log(optimizedCanConstruct('abcdef', ['ab', 'abc', 'cd', 'abcd'])); // true
99+
console.log(optimizedCanConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // false
100+
console.log(optimizedCanConstruct('enterapotentpot', ['a', 'p', 'ent', 'enter', 'ot', 'o', 't'])); // true
101+
console.log(optimizedCanConstruct('eeeeeeeeeeeeeeeeeeeeeeeeeef', ['e', 'ee', 'eee', 'eeee', 'eeeee', 'eeeeee'])); // false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* 02:38:35 - https://youtu.be/oBt53YbR9Kk?t=9515
3+
*
4+
* Problem:
5+
* Write a function `countConstruct(target, wordBank)` that accepts a target string and an array of strings.
6+
* The function should return the number of ways that the `target` can be constructed by concatenating elements of the `wordBank` array.
7+
* You may reuse elements of `wordBank` as many times as needed.
8+
*/
9+
10+
/**
11+
* Brute Force Approach
12+
* This function attempts to solve the problem using recursion without any optimizations.
13+
* @param {string} target - The target string we want to construct.
14+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
15+
* @returns {number} - Returns the number of ways the target can be constructed.
16+
*/
17+
function countConstruct(target, wordBank) {
18+
// Base case: If the target is an empty string, there is one way to construct it (by using no words).
19+
if (target === '') return 1;
20+
21+
let totalCount = 0;
22+
23+
// Iterate over each word in the wordBank
24+
for (const word of wordBank) {
25+
// Check if the word is a prefix of the target
26+
if (target.indexOf(word) === 0) {
27+
// If it is, we create a new target by removing the prefix (word)
28+
const numWaysForRest = countConstruct(target.slice(word.length), wordBank);
29+
// Add the number of ways to construct the rest of the target to the total count
30+
totalCount += numWaysForRest;
31+
}
32+
}
33+
34+
return totalCount;
35+
}
36+
37+
console.log("===== Brute Force =====");
38+
39+
// Brute Force
40+
// m = target.length
41+
// n = wordBank.length
42+
// Time Complexity: O(n^m * m)
43+
// In the worst case, we have to explore all combinations of the wordBank for each character in the target.
44+
// Space Complexity: O(m^2)
45+
// Due to the call stack and slicing of strings.
46+
console.log(countConstruct('purple', ['purp', 'p', 'ur', 'le', 'purpl'])); // 2
47+
console.log(countConstruct('abcdef', ['ab', 'abc', 'cd', 'abcd'])); // 1
48+
console.log(countConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // 0
49+
console.log(countConstruct('enterapotentpot', ['a', 'p', 'ent', 'enter', 'ot', 'o', 't'])); // 4
50+
console.log(countConstruct('eeeeeeeeeeeeeeeeeeeeeeeeeef', ['e', 'ee', 'eee', 'eeee', 'eeeee', 'eeeeee'])); // 0
51+
52+
/**
53+
* Optimized Approach using Memoization
54+
* This function optimizes the brute force approach by using memoization to store the results of subproblems.
55+
* @param {string} target - The target string we want to construct.
56+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
57+
* @param {object} memo - An object used to store the results of subproblems.
58+
* @returns {number} - Returns the number of ways the target can be constructed.
59+
*/
60+
function optimizedCountConstruct(target, wordBank, memo = {}) {
61+
// Check if the result for the current target is already in the memo
62+
if (target in memo) return memo[target];
63+
// Base case: If the target is an empty string, there is one way to construct it (by using no words).
64+
if (target === '') return 1;
65+
66+
let totalCount = 0;
67+
68+
// Iterate over each word in the wordBank
69+
for (const word of wordBank) {
70+
// Check if the word is a prefix of the target
71+
if (target.indexOf(word) === 0) {
72+
// If it is, we create a new target by removing the prefix (word)
73+
const numWaysForRest = optimizedCountConstruct(target.slice(word.length), wordBank, memo);
74+
// Add the number of ways to construct the rest of the target to the total count
75+
totalCount += numWaysForRest;
76+
}
77+
}
78+
79+
// Store the result in the memo and return the total count
80+
memo[target] = totalCount;
81+
return totalCount;
82+
}
83+
84+
console.log("===== Memoization =====");
85+
// Memoization
86+
// m = target.length
87+
// n = wordBank.length
88+
// Time Complexity: O(n * m^2)
89+
// For each character in the target (m), we iterate over the wordBank (n) and slice the string (m).
90+
// Space Complexity: O(m^2)
91+
// Due to the memo object and the call stack.
92+
console.log(optimizedCountConstruct('purple', ['purp', 'p', 'ur', 'le', 'purpl'])); // 2
93+
console.log(optimizedCountConstruct('abcdef', ['ab', 'abc', 'cd', 'abcd'])); // 1
94+
console.log(optimizedCountConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // 0
95+
console.log(optimizedCountConstruct('enterapotentpot', ['a', 'p', 'ent', 'enter', 'ot', 'o', 't'])); // 4
96+
console.log(optimizedCountConstruct('eeeeeeeeeeeeeeeeeeeeeeeeeef', ['e', 'ee', 'eee', 'eeee', 'eeeee', 'eeeeee'])); // 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* 02:47:30 - https://youtu.be/oBt53YbR9Kk?t=10050
3+
*
4+
*
5+
* Problem:
6+
* Write a function `allConstruct(target, wordBank)` that accepts a target string and an array of strings.
7+
* This function should return a 2D array containing all the ways that `target` can be constructed by concatenating elements of the `wordBank` array.
8+
* Each element of the 2D array should represent one combination that constructs the `target`
9+
* You may reuse elements of `wordBank` as many times as needed.
10+
*/
11+
12+
/**
13+
* Brute Force Approach
14+
* This function attempts to solve the problem using recursion without any optimizations.
15+
* @param {string} target - The target string we want to construct.
16+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
17+
* @returns {string[][]} - Returns a 2D array containing all the ways to construct the target.
18+
*/
19+
function allConstruct(target, wordBank) {
20+
// Base case: If the target is an empty string, return an array containing an empty array
21+
if (target === '') return [[]];
22+
23+
const result = [];
24+
25+
// Iterate over each word in the wordBank
26+
for (const word of wordBank) {
27+
// Check if the word is a prefix of the target
28+
if (target.indexOf(word) === 0) {
29+
// If it is, we create a new target by removing the prefix (word)
30+
const suffix = target.slice(word.length);
31+
// Recursively find all ways to construct the suffix
32+
const suffixWays = allConstruct(suffix, wordBank);
33+
// For each way to construct the suffix, add the current word to the beginning
34+
const targetWays = suffixWays.map(way => [word, ...way]);
35+
// Add all the ways to construct the target to the result array
36+
result.push(...targetWays);
37+
}
38+
}
39+
40+
return result;
41+
}
42+
43+
// Brute Force
44+
// m = target.length
45+
// n = wordBank.length
46+
// Time Complexity: O(n^m)
47+
// Each recursive call spawns n new recursive calls, leading to exponential time complexity.
48+
// Space Complexity: O(m)
49+
// The maximum depth of the recursion tree is m.
50+
console.log("===== Brute Force =====");
51+
console.log(allConstruct("purple", ["purp", "p", "ur", "le", "purpl"])); // [ [ 'purp', 'le' ], [ 'p', 'ur', 'p', 'le' ] ]
52+
console.log(allConstruct("abcdef", ["ab", "abc", "cd", "def", "abcd", "ef", "c"])); // [ [ 'ab', 'cd', 'ef' ], [ 'ab', 'c', 'def' ], [ 'abc', 'def' ], [ 'abcd', 'ef' ] ]
53+
console.log(allConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // []
54+
console.log(allConstruct('aaaaaaaaaaaaaaaaaaaaaaaaaaz', ['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa'])); // []
55+
56+
/**
57+
* Optimized Approach using Memoization
58+
* This function optimizes the brute force approach by using memoization to store the results of subproblems.
59+
* @param {string} target - The target string we want to construct.
60+
* @param {string[]} wordBank - The array of words that can be used to construct the target.
61+
* @param {object} memo - An object used to store the results of subproblems.
62+
* @returns {string[][]} - Returns a 2D array containing all the ways to construct the target.
63+
*/
64+
function optimizedAllConstruct(target, wordBank, memo = {}) {
65+
// Check if the result for the current target is already in the memo
66+
if (target in memo) return memo[target];
67+
// Base case: If the target is an empty string, return an array containing an empty array
68+
if (target === '') return [[]];
69+
70+
const result = [];
71+
72+
// Iterate over each word in the wordBank
73+
for (const word of wordBank) {
74+
// Check if the word is a prefix of the target
75+
if (target.indexOf(word) === 0) {
76+
// If it is, we create a new target by removing the prefix (word)
77+
const suffix = target.slice(word.length);
78+
// Recursively find all ways to construct the suffix
79+
const suffixWays = optimizedAllConstruct(suffix, wordBank, memo);
80+
// For each way to construct the suffix, add the current word to the beginning
81+
const targetWays = suffixWays.map(way => [word, ...way]);
82+
// Add all the ways to construct the target to the result array
83+
result.push(...targetWays);
84+
}
85+
}
86+
87+
// Store the result in the memo and return the total count
88+
memo[target] = result;
89+
return result;
90+
}
91+
92+
console.log("===== Memoization =====");
93+
// Memoization
94+
// m = target.length
95+
// n = wordBank.length
96+
// Time Complexity: O(n * m)
97+
// Each target string can be constructed in a number of ways proportional to its length, leading to polynomial time complexity.
98+
// Space Complexity: O(m)
99+
// Due to the memo object and the call stack.
100+
console.log(optimizedAllConstruct("purple", ["purp", "p", "ur", "le", "purpl"])); // [ [ 'purp', 'le' ], [ 'p', 'ur', 'p', 'le' ] ]
101+
console.log(optimizedAllConstruct("abcdef", ["ab", "abc", "cd", "def", "abcd", "ef", "c"])); // [ [ 'ab', 'cd', 'ef' ], [ 'ab', 'c', 'def' ], [ 'abc', 'def' ], [ 'abcd', 'ef' ] ]
102+
console.log(optimizedAllConstruct('skateboard', ['bo', 'rd', 'ate', 't', 'ska', 'sk', 'boar'])); // []
103+
console.log(optimizedAllConstruct('aaaaaaaaaaaaaaaaaaaaaaaaaaaz', ['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa'])); // []

dynamic_programming/06_can_construct.js

-68
This file was deleted.

0 commit comments

Comments
 (0)