Skip to content

Commit 519b72e

Browse files
bhq12walkccc
authored andcommitted
Update 15-2.md
1 parent c708c44 commit 519b72e

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

docs/Chap15/Problems/15-2.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,56 @@
22
>
33
> Give an efficient algorithm to find the longest palindrome that is a subsequence of a given input string. For example, given the input $\text{character}$, your algorithm should return $\text{carac}$. What is the running time of your algorithm?
44
5-
Let $A[1..n]$ denote the array which contains the given word. First note that for a palindrome to be a subsequence we must be able to divide the input word at some position $i$, and then solve the longest common subsequence problem on $A[1..i]$ and $A[i + 1..n]$, possibly adding in an extra letter to account for palindromes with a central letter. Since there are $n$ places at which we could split the input word and the $\text{LCS}$ problem takes time $O(n^2)$, we can solve the palindrome problem in time $O(n^3)$.
5+
Let $A[1..n]$ denote the array which contains the given word. Taking inspiration from the Longest-Common-Subsequence problem earlier in the chapter, we can consider each pair of indexes $i$ and $j$ such that $0 \le i < j < n$ as a decision point where each character-pair may be either included or excluded from the longest-palindromic substring.
6+
7+
Our recursion is defined as:
8+
9+
- If $A[i] = A[j]$, then characters $i$ and $j$ must be in the longest palindromic substring (else we contradict that our recursion solves for the longest possible substring)
10+
- If $A[i] \ne A[j]$, then the longest palindromic substring is found in one of $A[i + 1..j]$ or $A[i..j + 1]$, forming our recursive subproblems
11+
12+
Our recursive base case is the single-character palindrome, i.e. the case where $i = j$. From there we build our subproblems up taking one character-length step at a time until we reach $n$ our size of the initial array.
13+
14+
```cpp
15+
LPS-LENGTH(A, n)
16+
initialize a table LPS of size n by n
17+
initialize a table DECISIONS of size n by n
18+
19+
for i = 1 to n
20+
// Base case, a palindrome of length 1
21+
LPS[i][i] = 1
22+
DECISIONS[i][i] = "TAKE ONE"
23+
24+
for length = 1 to n
25+
for i = 0 to (n - length)
26+
j = i + length
27+
if A[i] == A[j]
28+
LPS[i][j] = 2 + LPS[i + 1][j - 1]
29+
DECISIONS[i][j] = "TAKE BOTH"
30+
else if LPS[i + 1][j] > LPS[i][j - 1]
31+
LPS[i][j] = LPS[i + 1][j]
32+
DECISIONS[i][j] = "IGNORE LEFT"
33+
else
34+
LPS[i][j] = LPS[i][j - 1]
35+
DECISIONS[i][j] = "IGNORE RIGHT"
36+
37+
return LPS, DECISIONS
38+
```
39+
40+
As is easily intuited by the above algorithm, our algorithm $O(n^2)$, needing to iterate over $n$ subproblem-lengths and having to compare $O(n)$ index pairs for each.
41+
42+
And then similarly to the Longest-Common-Subsequence problem again, we can traverse the $\text{DECISIONS}$ matrix to reconstruct our palindrome:
43+
44+
```cpp
45+
PRINT-LPS(A, DECISIONS, i, j)
46+
if DECISIONS[i][j] == "TAKE ONE":
47+
print A[i]
48+
else if DECISIONS[i][j] == "TAKE BOTH":
49+
print A[i]
50+
PRINT-LCS(A, DECISIONS, i + 1, j - 1)
51+
print A[j]
52+
else if DECISIONS[i][j] == "IGNORE LEFT":
53+
PRINT-LCS(A, DECISIONS, i + 1, j)
54+
else
55+
// IGNORE_RIGHT
56+
PRINT-LCS(A, DECISIONS, i, j - 1)
57+
```

0 commit comments

Comments
 (0)