Skip to content

Commit 9e67e3a

Browse files
Added DP solution for longest palindromic subsequence.
1 parent c031f7f commit 9e67e3a

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ Happy to accept any contributions to this in any langugage.
156156
* MaximumRibbonCut_2.ts)
157157
9. Find Longest Palindromic Subsequence
158158
* [Solution Brute Force](./dynamic_programming/LongestPalindromicSubsequence_1.ts)
159-
159+
* [Solution DP Top Down](./dynamic_programming/LongestPalindromicSubsequence_2.ts)
160+
* [Solution DP Bottoms Up](./dynamic_programming/LongestPalindromicSubsequence_3.ts)
160161

161162
# TODO Items (More topics to explore further)
162163
* [All TODO Items](./TODO.md)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
*
3+
* Problem: Given a string of "n" characters, find the longest palindromic subsequence
4+
* of the input string. The subsequnce can remove one or more elements from the original
5+
* string retaining the original order of the string. This is a very different problem
6+
* from finding the longest palindromic substring without the constraint of removing any
7+
* elements.
8+
*
9+
* Use the brute force to generate all possible subsequences. While in a subsequence,
10+
* if the string is already a palindrome from the ends, continue proceeding inwards.
11+
* If it is not palindrome from the end, we can continue ignoring one elements from
12+
* the left and right to see if we can achieve a palindromic subsequence. while the brute
13+
* force exploration happens, we need to cache all the pre-computed results in an
14+
* additional DP storage for use.
15+
*
16+
* Complexity....
17+
* Time: O(n^2) since beg * end is the worst case of computation, rest of the computations
18+
* are cached. Space: O(n^2 + n) since in the worst case, we would have all the n^2 positions
19+
* cahced and stored. Additionally, O(n) space would be used for the recursion stack.
20+
*
21+
* @param input
22+
*/
23+
function findLongestPalSubseq1(input: string) {
24+
return findLongestPalSubseqHelper1(input, 0, input.length - 1);
25+
}
26+
27+
function findLongestPalSubseqHelper1(input: string, beg: number, end: number, dp: number[][] = []): number {
28+
29+
dp[beg] = dp[beg] || [];
30+
31+
if (dp[beg][end] !== undefined)
32+
return dp[beg][end];
33+
34+
if (end < beg) return 0;
35+
else if (end === beg) return 1;
36+
else if (input[beg] === input[end]) {
37+
// Ends are matching, continue inwards.
38+
dp[beg][end] = 2 + findLongestPalSubseqHelper1(input, beg + 1, end - 1);
39+
return dp[beg][end]
40+
}
41+
42+
// If the ends are not matching, we may try to skip an element from the end, to attempt
43+
// to make a palindromic string
44+
const maxWithLeftInclusion = findLongestPalSubseqHelper1(input, beg + 1, end);
45+
const maxWithRightInclusion = findLongestPalSubseqHelper1(input, beg, end - 1);
46+
dp[beg][end] = Math.max(maxWithLeftInclusion, maxWithRightInclusion);
47+
return dp[beg][end];
48+
}
49+
50+
function testLongestPlalindSubseq1(input: string) {
51+
console.log(`Longest Palindromic Subsequence for input ${input}: ${findLongestPalSubseq1(input)}`)
52+
}
53+
54+
testLongestPlalindSubseq1("abdbca")
55+
testLongestPlalindSubseq1("cddpd")
56+
testLongestPlalindSubseq1("pqr")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
*
3+
* Problem: Given a string of "n" characters, find the longest palindromic subsequence
4+
* of the input string. The subsequnce can remove one or more elements from the original
5+
* string retaining the original order of the string. This is a very different problem
6+
* from finding the longest palindromic substring without the constraint of removing any
7+
* elements.
8+
*
9+
* Bottoms up dynamic programming is solution is used for identifying the max subsequence.
10+
* We start by including one character at a time. With each iteration, we include one more
11+
* character. Wuth each new character, there are n^2 possible subsequences, we create those
12+
* possible subsequences. With each subsequence, we identify the max palindromic length
13+
* using earlier computation and preserved results.
14+
*
15+
* Complexity....
16+
* Time: O(n^2) since we are creating all the possible subsequences
17+
* Space: O(n^2) since in the worst case, we would have to store the results of the entire possible combination.
18+
* @param input
19+
*/
20+
function findLongestPalSubseq2(input: string) {
21+
return findLongestPalSubseqHelper2(input);
22+
}
23+
24+
function findLongestPalSubseqHelper2(input: string): number {
25+
26+
const dp: number[][] = Array.from({length: input.length}, () => Array(input.length).fill(0));
27+
for (let idx = 0; idx < input.length; idx++)
28+
dp[idx][idx] = 1;
29+
30+
/**
31+
* DP table is built by including one additional position at each step.
32+
* We start from right to left, in order to use the DP formulation function.
33+
* At each character that is included, we need to consider its pair of subsequences
34+
* with all the other positions/characters identified before.
35+
*/
36+
for (let beg = input.length - 1; beg >= 0; beg--) {
37+
for (let end = beg + 1; end < input.length; end++) {
38+
if (input[beg] === input[end]) {
39+
// If the perfect palindrome is created from the end, we squeeze.
40+
dp[beg][end] = dp[beg + 1][end - 1] + 2;
41+
} else {
42+
// If not, we see the max possible from either left or right.
43+
dp[beg][end] = Math.max(dp[beg + 1][end], dp[beg][end - 1]);
44+
}
45+
}
46+
}
47+
48+
return dp[0][input.length - 1];
49+
}
50+
51+
function testLongestPlalindSubseq2(input: string) {
52+
console.log(`Longest Palindromic Subsequence for input ${input}: ${findLongestPalSubseq2(input)}`)
53+
}
54+
55+
testLongestPlalindSubseq2("abdbca")
56+
testLongestPlalindSubseq2("cddpd")
57+
testLongestPlalindSubseq2("pqr")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy