You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- The <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` represents the total number.
4029
4029
- The <b>space complexity</b> is `O(n)`, which will be used to store the <i>recursion stack</i>.
4030
-
### Top-down Dynamic Programming with Memoization#
4030
+
### Top-down Dynamic Programming with Memoization
4031
4031
We can memoize both functions `findMPPCutsRecursive()` and `isPalindrome()`. The two changing values in both these functions are the two indexes; therefore, we can store the results of all the <i>subproblems</i> in a two-dimensional array. (alternatively, we can use a <i>hash-table</i>).
// Explanation: We do not need to cut, as "pp" is a palindrome.
4101
4101
```
4102
-
### Bottom-up Dynamic Programming#
4102
+
### Bottom-up Dynamic Programming
4103
4103
The above solution tells us that we need to build two tables, one for the `isPalindrome()` and one for `findMPPCuts()`.
4104
4104
4105
4105
If you remember, we built a table in the [Longest Palindromic Substring (LPS)](#longest-palindromic-subsequence) chapter that can tell us what <i>substrings</i> (of the input <i>string</i>) are <i>palindrome</i>. We will use the same approach here to build the table required for `isPalindrome()`.
> Given two strings `s1` and `s2`, find the length of the longest <b>substring</b> which is common in both the strings.
4190
+
4191
+
#### Example 1:
4192
+
```js
4193
+
Input: s1 ="abdca"
4194
+
s2 ="cbda"
4195
+
Output:2
4196
+
Explanation: The longest common substring is "bd".
4197
+
```
4198
+
#### Example 2:
4199
+
```js
4200
+
Input: s1 ="passport"
4201
+
s2 ="ppsspt"
4202
+
Output:3
4203
+
Explanation: The longest common substring is "ssp".
4204
+
```
4205
+
### Brute-Force Solution
4206
+
A basic <b>brute-force solution</b> could be to try all substrings of `s1` and `s2` to find the longest common one. We can start matching both the strings one character at a time, so we have two options at any step:
4207
+
4208
+
1. If the strings have a matching character, we can <i>recursively</i> match for the remaining lengths and keep a track of the current matching length.
4209
+
2. If the strings don’t match, we start two new <i>recursive calls</i> by skipping one character separately from each string and reset the matching length.
4210
+
4211
+
The length of the <b>Longest Common Substring (LCS)</b> will be the maximum number returned by the three <i>recurse calls</i> in the above two options.
`Length of Longest Common Substring: ---> ${findLCSLength('abdca', 'cbda')}`
4252
+
);
4253
+
// Output: 2
4254
+
// Explanation: The longest common substring is "bd".
4255
+
4256
+
console.log(
4257
+
`Length of Longest Common Substring: ---> ${findLCSLength(
4258
+
'passport',
4259
+
'ppsspt'
4260
+
)}`
4261
+
);
4262
+
// Output: 3
4263
+
// Explanation: The longest common substring is "ssp".
4264
+
```
4265
+
4266
+
- Because of the three <i>recursive calls</i>, the <b>time complexity</b> of the above algorithm is exponential `O(3ᵐ⁺ⁿ)`, where `m` and `n` are the lengths of the two input strings. The <b>space complexity</b> is `O(m+n)`, this <b>space</b> will be used to store the <i>recursion stack</i>.
4267
+
4268
+
### Top-down Dynamic Programming with Memoization
4269
+
We can use an array to store the already solved <i>subproblems</i>.
4270
+
4271
+
The three changing values to our <i>recursive function</i> are the two indexes (`index1` and `index2`) and the `count`. Therefore, we can store the results of all <i>subproblems</i>in a <i>three-dimensional array</i>. (Another alternative could be to use a <i>hash-table</i> whose key would be a string (`index1` + `“|”``index2` + `“|”` + `count`)).
`Length of Longest Common Substring: ---> ${findLCSLength('abdca', 'cbda')}`
4325
+
);
4326
+
// Output: 2
4327
+
// Explanation: The longest common substring is "bd".
4328
+
4329
+
console.log(
4330
+
`Length of Longest Common Substring: ---> ${findLCSLength(
4331
+
'passport',
4332
+
'ppsspt'
4333
+
)}`
4334
+
);
4335
+
// Output: 3
4336
+
// Explanation: The longest common substring is "ssp".
4337
+
```
4338
+
4339
+
### Bottom-up Dynamic Programming
4340
+
Since we want to match all the <i>substrings</i> of the given two <i>strings</i>, we can use a two-dimensional array to store our results. The lengths of the two <i>strings</i> will define the size of the two dimensions of the array. So for every index `index1` in string `s1` and `index2` in string `s2`, we have two options:
4341
+
4342
+
1. If the character at `s1[index1]` matches `s2[index2]`, the length of the <i>common substring<i> would be one plus the length of the <i>common substring<i> till `index1-1` and `index2-1` indexes in the two <i>strings</i>.
4343
+
2. If the character at the `s1[index1]` does not match `s2[index2]`, we don’t have any <i>common substring<i>.
4344
+
So our <i>recursive formula<i> would be:
4345
+
4346
+
```js
4347
+
if s1[index1] == s2[index2]
4348
+
dp[index1][index2] =1+ dp[index1-1][index2-1]
4349
+
else
4350
+
dp[index1][index2] =0
4351
+
```
4352
+
we can clearly see that the <b>longest common substring</b> is of length `2`-- as shown by `dp[3][3]`. Here is the code for our <b>bottom-up dynamic programming approach</b>:
4353
+
```js
4354
+
functionfindLCSLength(str1, str2) {
4355
+
constdp=Array(str1.length+1)
4356
+
.fill(0)
4357
+
.map(() =>Array(str2.length+1).fill(0));
4358
+
let maxLength =0;
4359
+
4360
+
for (let i =1; i <=str1.length; i++) {
4361
+
for (let j =1; j <=str2.length; j++) {
4362
+
if (str1.charAt(i -1) ===str2.charAt(j -1)) {
4363
+
dp[i][j] =1+ dp[i -1][j -1];
4364
+
maxLength =Math.max(maxLength, dp[i][j]);
4365
+
}
4366
+
}
4367
+
}
4368
+
4369
+
return maxLength;
4370
+
}
4371
+
4372
+
console.log(
4373
+
`Length of Longest Common Substring: ---> ${findLCSLength('abdca', 'cbda')}`
4374
+
);
4375
+
// Output: 2
4376
+
// Explanation: The longest common substring is "bd".
4377
+
4378
+
console.log(
4379
+
`Length of Longest Common Substring: ---> ${findLCSLength(
4380
+
'passport',
4381
+
'ppsspt'
4382
+
)}`
4383
+
);
4384
+
// Output: 3
4385
+
// Explanation: The longest common substring is "ssp".
4386
+
```
4387
+
4388
+
- The <b>time and space complexity</b> of the above algorithm is `O(m∗n)`, where `m` and `n` are the lengths of the two input <i>strings</i>.
4389
+
4390
+
### Challenge
4391
+
Can we further improve our <b>bottom-up DP</b> solution? Can you find an algorithm that has `O(n)` <b>space complexity</b?
0 commit comments