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 above solution has <b>time and space complexity</b> of `O(n)`.
3230
3230
#### Memory optimization
3231
-
We can optimize the space used in our previous solution. We don’t need to store all the previous numbers up to `n`, as we only need two previous numbers to calculate the next number in the sequence. Let’s use this fact to further improve our solution:
3231
+
We can optimize the space used in our previous solution. We don’t need to store all the previous numbers up to `n`, as we only need two previous numbers to calculate the next number in the <b>sequence</b>. Let’s use this fact to further improve our solution:
3232
3232
3233
3233
```js
3234
3234
functionfindMaxSteal(wealth) {
@@ -3256,24 +3256,24 @@ We can clearly see that this problem follows the <b>[Fibonacci number pattern](#
> Given a sequence, find the length of its <b>Longest Palindromic Subsequence (LPS)</b>. In a <b>palindromic subsequence</b>, <i>elements read the same backward and forward</i>.
3259
+
> Given a <b>sequence</b>, find the length of its <b>Longest Palindromic Subsequence (LPS)</b>. In a <b>palindromic subsequence</b>, <i>elements read the same backward and forward</i>.
3260
3260
3261
3261
A <b>subsequence</b> is a <i>sequence</i> that can be derived from another <i>sequence</i> by <i>deleting some or no elements without changing the order of the remaining elements</i>.
3262
3262
3263
3263
#### Example 1:
3264
-
```
3264
+
```js
3265
3265
Input:"abdbca"
3266
3266
Output:5
3267
3267
Explanation:LPS is "abdba".
3268
3268
```
3269
3269
#### Example 2:
3270
-
```
3270
+
```js
3271
3271
Input:="cddpd"
3272
3272
Output:3
3273
3273
Explanation:LPS is "ddd".
3274
3274
```
3275
3275
#### Example 3:
3276
-
```
3276
+
```js
3277
3277
Input:="pqr"
3278
3278
Output:1
3279
3279
Explanation:LPS could be "p", "q" or "r".
@@ -3322,7 +3322,7 @@ findLPSLength('pqr');
3322
3322
// Output: 1
3323
3323
// Explanation: LPS could be "p", "q" or "r".
3324
3324
```
3325
-
- In each function call, we are either having one <i>recursive call</i> or <i>two recursive calls</i> (we will never have <i>three recursive calls</i>); hence, the <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` is the length of the input sequence. The <b>space complexity</b> is `O(n)`, which is used to store the <i>recursion stack</i>.
3325
+
- In each function call, we are either having one <i>recursive call</i> or <i>two recursive calls</i> (we will never have <i>three recursive calls</i>); hence, the <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` is the length of the input <i>sequence</i>. The <b>space complexity</b> is `O(n)`, which is used to store the <i>recursion stack</i>.
3326
3326
3327
3327
### Top-down Dynamic Programming with Memoization
3328
3328
We can use an array to store the already solved <i>subproblems</i>.
@@ -3372,19 +3372,20 @@ findLPSLength('pqr');
3372
3372
// Output: 1
3373
3373
// Explanation: LPS could be "p", "q" or "r".
3374
3374
```
3375
-
- Since our memoization array `dp[str.length][str.length]` stores the results for all the <i>subproblems</i>, we can conclude that we will not have more than `N*N` <i>subproblems</i>(where `N` is the length of the input sequence). This means that our time complexity will be `O(N²)`.
3375
+
- Since our <b>memoization</b> array `dp[str.length][str.length]` stores the results for all the <i>subproblems</i>, we can conclude that we will not have more than `N*N` <i>subproblems</i>(where `N` is the length of the input <i>sequence</i>). This means that our time complexity will be `O(N²)`.
3376
3376
- The above algorithm will be using `O(N²)` <b>space</b> for the <b>memoization</b> array. Other than that we will use `O(N)` <b>space</b> for the <i>recursion call-stack</i>. So the total <b>space complexity</b> will be `O(N² +N)`, which is asymptotically equivalent to `O(N²)`.
3377
3377
3378
3378
### Bottom-up Dynamic Programming
3379
-
Since we want to try all the subsequences of the given sequence, we can use a two-dimensional array to store our results. We can start from the beginning of the sequence and keep adding one element at a time. At every step, we will try all of its subsequences. So for every `startIndex` and `endIndex` in the given string, we will choose one of the following two options:
3379
+
Since we want to try all the <b>subsequences</b> of the given <i>sequence</i>, we can use a two-dimensional array to store our results. We can start from the beginning of the <i>sequence</i> and keep adding one element at a time. At every step, we will try all of its <b>subsequences</b>. So for every `startIndex` and `endIndex` in the given string, we will choose one of the following two options:
3380
3380
3381
-
1. If the element at the `startIndex` matches the element at the `endIndex`, the length of <b>LPS</b> would be two plus the length of <b>LPS</b> till`startIndex+1`` and endIndex-1`.
3381
+
1. If the element at the `startIndex` matches the element at the `endIndex`, the length of <b>LPS</b> would be two plus the length of <b>LPS</b> until`startIndex+1` and `endIndex-1`.
3382
3382
2. If the element at the `startIndex` does not match the element at the `endIndex`, we will take the maximum <b>LPS</b> created by either skipping element at the `startIndex` or the `endIndex`.
> Given a string, find the length of its <b>Longest Palindromic Substring (LPS)</b>. In a <i>palindromic</i> string, <i>elements read the same backward and forward</i>.
3441
+
3442
+
#### Example 1:
3443
+
```
3444
+
Input:"abdbca"
3445
+
Output:3
3446
+
Explanation:LPS is "bdb".
3447
+
```
3448
+
#### Example 2:
3449
+
```
3450
+
Input:="cddpd"
3451
+
Output:3
3452
+
Explanation:LPS is "dpd".
3453
+
```
3454
+
#### Example 3:
3455
+
```
3456
+
Input:="pqr"
3457
+
Output:1
3458
+
Explanation:LPS could be "p", "q" or "r".
3459
+
```
3460
+
### Basic Brute-Force Solution
3461
+
This problem follows the <b>[Longest Palindromic Subsequence pattern](#pattern-4-palindromic-subsequence)</b>. The only difference is that in a <i>palindromic subsequence</i> characters can be non-adjacent, whereas in a <i>substring</i> all characters should form a <i>palindrome</i>. We will follow a similar approach though.
3462
+
3463
+
The <b>basic brute-force solution</b> will be to try all the <i>substrings</i> of the given string. We can start processing from the beginning and the end of the string. So at any step, we will have two options:
3464
+
3465
+
1. If the element at the beginning and the end are the same, we make a <i>recursive call</i> to check if the remaining <i>substring</i> is also a <i>palindrome</i>. If so, the <i>substring</i> is a <i>palindrome</i> from beginning to end.
3466
+
2. We will skip either the element from the beginning or the end to make two <i>recursive calls</i> for the remaining <i>substring</i>. The length of <b>LPS</b> would be the maximum of these two <i>recursive calls</i>.
console.log('Length of LPS ---> '+findLPSLength('abdbca'));
3501
+
// Output: 3
3502
+
// Explanation: LPS is "bdb".
3503
+
3504
+
console.log('Length of LPS ---> '+findLPSLength('cddpd'));
3505
+
// Output: 3
3506
+
// Explanation: LPS is "dpd".
3507
+
3508
+
console.log('Length of LPS ---> '+findLPSLength('pqr'));
3509
+
// Output: 1
3510
+
// Explanation: LPS could be "p", "q" or "r".
3511
+
```
3512
+
- Due to the three <b>recursive calls</b>, the <b>time complexity</b> of the above algorithm is exponential `O(3ⁿ)`, where `n` is the length of the input string.
3513
+
- The <b>space complexity</b> is `O(n)` which is used to store the <b>recursion stack</b>.
3514
+
3515
+
### Top-down Dynamic Programming with Memoization
3516
+
We can use an array to store the already solved <i>subproblems</i>.
3517
+
3518
+
The two changing values to our <b>recursive function</b> are the two indexes, `startIndex` and `endIndex`. Therefore, we can store the results of all the <i>subproblems</i> in a two-dimensional array. (Another alternative could be to use a <i>hash-table</i> whose key would be a string (`startIndex + “|” + endIndex`))
console.log('Length of LPS ---> '+findLPSLength('abdbca'));
3558
+
// Output: 3
3559
+
// Explanation: LPS is "bdb".
3560
+
3561
+
console.log('Length of LPS ---> '+findLPSLength('cddpd'));
3562
+
// Output: 3
3563
+
// Explanation: LPS is "dpd".
3564
+
3565
+
console.log('Length of LPS ---> '+findLPSLength('pqr'));
3566
+
// Output: 1
3567
+
// Explanation: LPS could be "p", "q" or "r".
3568
+
```
3569
+
- The above algorithm has a <b>time and space complexity</b> of `O(n²)` because we will not have more than `n∗n` <i>subproblems</i>.
3570
+
3571
+
### Bottom-up Dynamic Programming
3572
+
Since we want to try all the <i>substrings</i> of the given string, we can use a two-dimensional array to store the <i>subproblems’</i> results. So `dp[i][j]` will be `true` if the <i>substring</i> from index `i` to index `j` is a <i>palindrome</i>.
3573
+
3574
+
We can start from the beginning of the string and keep adding one element at a time. At every step, we will try all of its <i>substrings</i>. So for every `endIndex` and `startIndex` in the given string, we need to check the following thing:
3575
+
3576
+
- If the element at the `startIndex` matches the element at the `endIndex`, we will further check if the remaining <i>substring</i> (from `startIndex+1` to `endIndex-1`) is a <i>substring</i> too.
3577
+
3578
+
So our <i>recursive</i> formula will look like:
3579
+
```js
3580
+
if st[startIndex] == st[endIndex], and
3581
+
if the remaing string is of zero length or dp[startIndex+1][endIndex-1] is a palindrome then
3582
+
3583
+
dp[startIndex][endIndex] =true
3584
+
```
3585
+
3586
+
Here is the code for our <b>bottom-up dynamic programming approach</b>:
3587
+
```js
3588
+
functionfindLPSLength(str) {
3589
+
// dp[i][j] will be 'true' if the string from index 'start' to index 'end' is a palindrome
3590
+
constdp=Array(str.length)
3591
+
.fill(0)
3592
+
.map(() =>Array(str.length).fill(0));
3593
+
//every string with one character is a palindrome
3594
+
for (let start =0; start <str.length; start++) {
3595
+
dp[start][start] =true;
3596
+
}
3597
+
3598
+
let maxLength =1;
3599
+
3600
+
for (let startIndex =str.length-1; startIndex >=0; startIndex--) {
3601
+
for (let endIndex = startIndex +1; endIndex <str.length; endIndex++) {
3602
+
if (str.charAt(startIndex) ===str.charAt(endIndex)) {
3603
+
//if it's a two character string or if the
3604
+
//remain string is a palindrome too
3605
+
if (endIndex - startIndex ===1|| dp[startIndex +1][endIndex -1]) {
console.log('Length of LPS ---> '+findLPSLength('abdbca'));
3616
+
// Output: 3
3617
+
// Explanation: LPS is "bdb".
3618
+
3619
+
console.log('Length of LPS ---> '+findLPSLength('cddpd'));
3620
+
// Output: 3
3621
+
// Explanation: LPS is "dpd".
3622
+
3623
+
console.log('Length of LPS ---> '+findLPSLength('pqr'));
3624
+
// Output: 1
3625
+
// Explanation: LPS could be "p", "q" or "r".
3626
+
```
3627
+
3628
+
- The <b>time and space complexity</b> of the above algorithm is `O(n²)`, where `n` is the length of the input string.
3629
+
3630
+
#### Manacher’s Algorithm
3631
+
The best-known algorithm to find the <b>[longest palindromic substring](#👩🏽🦯-longest-palindromic-substring)</b> which runs in linear time `O(n)` is <b>[Manacher’s Algorithm](https://en.wikipedia.org/wiki/Longest_palindromic_substring)</b>. However, it is a non-trivial algorithm that doesn’t use <b>DP</b>. Please take a look to familiarize yourself with this algorithm, however, no one expects you to come up with such an algorithm in a 45 minutes coding interview.
0 commit comments