Reputation: 5153
I want to find out the longest palindromic subsequence in a string. Everywhere I find the algorithm to find out the length of the subsequence, with the statement that the algo can be extended to return the subsequence as well, but nowhere have I found how. Can anybody explain how can I get the sequence as well?
Upvotes: 5
Views: 11160
Reputation: 757
Since you mentioned the link Longest Palindromic Subsequence in geeksforgeeks, I modified the solution to output the result. I think we need one auxiliary two-dimensions array to stored how the palindromic subsequence comes from, so we can get the result through the auxiliary array at last. You can see the logic in the below code:
#include<iostream>
#include<cstring>
using namespace std;
// A utility function to get max of two integers
int max (int x, int y) { return (x > y)? x : y; }
// Returns the length of the longest palindromic subsequence in seq
int lps(char *str,char *result)
{
int n = strlen(str);
int i, j, cl;
int L[n][n]; // Create a table to store results of subproblems
int Way[n][n];// Store how the palindrome come from.
// Strings of length 1 are palindrome of lentgh 1
for (i = 0; i < n; i++)
{
L[i][i] = 1;
Way[i][i]=0;
}
// Build the table. Note that the lower diagonal values of table are
// useless and not filled in the process. The values are filled in a
// manner similar to Matrix Chain Multiplication DP solution (See
// http://www.geeksforgeeks.org/archives/15553). cl is length of
// substring
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
{
L[i][j] = 2;
Way[i][j]=0;
}
else if (str[i] == str[j])
{
L[i][j] = L[i+1][j-1] + 2;
Way[i][j]=0;
}
else
{
if(L[i][j-1]>L[i+1][j])
{
L[i][j]=L[i][j-1];
Way[i][j]=1;
}
else
{
L[i][j]=L[i+1][j];
Way[i][j]=2;
}
}
}
}
int index=0;
int s=0,e=n-1;
while(s<=e)
{
if(Way[s][e]==0)
{
result[index++]=str[s];
s+=1;
e-=1;
}
else if(Way[s][e]==1)e-=1;
else if(Way[s][e]==2)s+=1;
}
int endIndex = (L[0][n - 1] % 2) ? index - 1 : index;
for (int k=0; k < endIndex; ++k)
result[L[0][n - 1] - 1 - k] = result[k];
result[index+endIndex]='\0';
return L[0][n-1];
}
/* Driver program to test above functions */
int main()
{
char seq[] = "GEEKSFORGEEKS";
char result[20];
cout<<"The lnegth of the LPS is "<<lps(seq,result)<<":"<<endl;
cout<<result<<endl;
getchar();
return 0;
}
Hope it helps!
Below is the explanation:
Let X[0..n-1] be the input sequence of length n and L(0, n-1) be the length of the longest palindromic sub-sequence of X[0..n-1].
There are 5 cases in total.
1)Every single character is a palindrome of length 1. L(i, i) = 1 for all indexes i in given sequence.
2)There are only 2 characters and both are same. L(i, j) = 2.
3)There are more than two characters, and first and last characters are the same L(i, j) = L(i + 1, j - 1) + 2
4)First and last characters are not the same and L(i + 1, j)< L(i, j - 1). L(i, j) = L(i, j - 1).
5)First and last characters are not the same and L(i + 1, j)>=L(i, j - 1). L(i, j) = L(i + 1, j).
We can observed that only in case 1,2 and 3, the character X[i] is included in the final result. We used a two-dimension auxiliary array to represent how the palindromic sub-sequence comes from. value 0 for case 1,2,3; value 1 for case 4; value 2 for case 5.
With the auxiliary array Way. We can get the result as below:
Let two variables s=0 and e=n-1.
While s<=e
Loop
If Way[s][e]==0 Then X[s] should be included in the result and we store it in our result array.
Else if Way[s][e]==1 Then X[s] should not be include in the result and update e=e-1 (because our result comes from case 4).
Else if Way[s][e]==2 Then X[s] should not be include in the result and update s=s+1 (because our result comes from case 5).
The loop should be terminated when s>e. In that way we can get half part of the result and we can easily extend it to get the whole result.
Upvotes: 8
Reputation: 92
A sample java implementation. Feel free to be brutal with your review comments.
public class LongestPalindrome {
public static void main(String... arguments) {
final String content = "GOBANANAS";
String palindrome = getLongestPalindrome(content);
System.out.println(palindrome);
}
private static String getLongestPalindrome(final String content) {
String lastPalindrome = "";
for (int lastIndex = content.length(); lastIndex >= 0; lastIndex--) {
for (int i = 0; i <= lastIndex; i++) {
String part = content.substring(i, lastIndex);
if (part.length() > lastPalindrome.length() && part.length() > 1) {
boolean isPalindrome = isPalindrome(part);
if (isPalindrome) {
lastPalindrome = part;
System.out.println(String.format("%s : %s", part, isPalindrome));
}
}
}
}
return lastPalindrome;
}
private static boolean isPalindrome(String string) {
String reverse = (new StringBuilder(string)).reverse().toString();
return (string.equals(reverse));
}
}
Upvotes: 0
Reputation: 1
A Java approach .Building the string from the LPS matrix generated during calculation of length of the palindromic sub-sequence.
private static void LongestPalindromicSubsequence(char a[])
{
int len=a.length;
int lps[][]=new int[len][len];
int l=1;
for(int i=0;i<len;i++)
{
lps[i][i]=1; //---------> Length of subsequence of string of length=1 is 1 <------------
}
for(int subsLen=2;subsLen<=len;subsLen++)
{
for( int i=0;i<(len-subsLen+1);i++)
{
int j=i+subsLen-1;
if(a[i]==a[j]&&subsLen==2)
{
lps[i][j]=2;
}
else
{
if(a[i]!=a[j])
{
lps[i][j]=Math.max(lps[i+1][j],lps[i][j-1]);
}
else
{
lps[i][j]=2+lps[i+1][j-1];
}
}
}
}
// System.out.println("Length of longest Palindromic subsequence: "+lps[0][len-1]);
printLongestPalindromicsubsequence(a,lps);
}
private static void printLongestPalindromicsubsequence(char[] a, int[][] lps)
{
int len=a.length;
int end=lps[0][len-1];
char str[]=new char[end+1];
str[end--]='\0';
int i=0,j=len-1;
while(end>=0&&i<=j)
{
if(a[i]==a[j])
{
str[end--]=a[i];
i++;
j--;
}
else
{
if(lps[i+1][j]>lps[i][j-1])
{
i++;
}
else
{
j--;
}
}
}
if(lps[0][len-1]%2!=0)
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>mid)
{
str[i++]=str[j--];
}
}
else
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>=mid)
{
str[i++]=str[j--];
}
}
for(i=0;i<str.length;i++)
System.out.print(str[i]);
}
Upvotes: 0
Reputation: 271
The below solution is pretty straight forward and requires no additional use of any other matrix. Here we are just tracing back our path to generate the longest palindromic sub sequence.
int lps(char *str)
{
int n = strlen(str);
int i, j, cl;
int L[n][n];
for (i = 0; i < n; i++)
L[i][i] = 1;
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
L[i][j] = 2;
else if (str[i] == str[j])
L[i][j] = L[i+1][j-1] + 2;
else
L[i][j] = max(L[i][j-1], L[i+1][j]);
}
}
cout<<L[0][n-1]<<endl;
i = 0,j = n-1;
vector<char> result;
while(i<=j)
{
if(str[i]==str[j])
{
result.push_back(str[i]);
i++,j--;
}
else if(L[i][j-1]>L[i+1][j])
{
j--;
}
else
{
i++;
}
}
if(L[0][n-1]%2==0)
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
else
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
result.erase(result.begin());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
}
Upvotes: 1
Reputation: 1191
Keep a backpointer as well as a value in your dynamic programming table for each cell. Then follow the traceback from the end of the table to reconstruct the subsequence.
Upvotes: 4
Reputation: 5917
The trick works like this:
Note that by definition of your second string, the LCS of both strings is the longest palindrome as well.
Upvotes: 1