38

Here is the problem (6.7 ch6 ) from Algorithms book (by Vazirani) that slightly differs from the classical problem that finding longest palindrome. How can I solve this problem ?

A subsequence is palindromic if it is the same whether read left to right or right to left. For instance, the sequence

A,C,G,T,G,T,C,A,A,A,A,T,C,G

has many palindromic subsequences, including A,C,G,C,A and A,A,A,A (on the other hand, the subsequence A,C,T is not palindromic). Devise an algorithm that takes a sequence x[1 ...n] and returns the (length of the) longest palindromic subsequence. Its running time should be O(n^2)

Community
  • 1
  • 1
  • 1
    I will recommend you give this a look, it's a paper about finding longest palindrome in linear time. (http://www.akalin.cx/longest-palindrome-linear-time) – Shane Hsu Nov 05 '12 at 04:46
  • 2
    It seems that "subsequence" in your meaning of the word means that `abcxxba` has `abcba` as the longest palindromic subsequence - is that correct? Because in that case the accepted answer appears to me to be wrong... – Floris Nov 16 '13 at 17:06
  • C++ based solution here - https://stackoverflow.com/a/44542960/1874627 – saurabheights Jun 14 '17 at 11:06

9 Answers9

77

This can be solved in O(n^2) using dynamic programming. Basically, the problem is about building the longest palindromic subsequence in x[i...j] using the longest subsequence for x[i+1...j], x[i,...j-1] and x[i+1,...,j-1] (if first and last letters are the same).

Firstly, the empty string and a single character string is trivially a palindrome. Notice that for a substring x[i,...,j], if x[i]==x[j], we can say that the length of the longest palindrome is the longest palindrome over x[i+1,...,j-1]+2. If they don't match, the longest palindrome is the maximum of that of x[i+1,...,j] and y[i,...,j-1].

This gives us the function:

longest(i,j)= j-i+1 if j-i<=0,
              2+longest(i+1,j-1) if x[i]==x[j]
              max(longest(i+1,j),longest(i,j-1)) otherwise

You can simply implement a memoized version of that function, or code a table of longest[i][j] bottom up.

This gives you only the length of the longest subsequence, not the actual subsequence itself. But it can easily be extended to do that as well.


MAK
  • 26,140
  • 11
  • 55
  • 86
  • 4
    I think it should be `2 + ...` when they match and `j-i if j-i<=1`. – Chris Hopman Jan 25 '11 at 08:38
  • How is this an O(n^2) algorithm? Wouldn't an input of N distinct characters result into an exponential growth of recursive calls? Could anyone please explain this? – srbhkmr Aug 09 '12 at 10:21
  • 1
    @srbh.kmr: That is why you need to memoize the function, or build the table bottom up. The table longest[i][j] has O(N^2) cells, so if you visit each state only once, the algorithm is O(N^2). – MAK Aug 09 '12 at 19:45
  • I think you can't say "2+longest(i+1,j-1) if x[i]==x[j]". If x[i+1...j-1] is not a palindrome, x[i]==x[j] doesn't add the longest value, which means the length can't be added by 2. i.e. If the string like "ABCA", x[0]==x[3], but longest(0,3) != 2. – Hao Liu Mar 06 '13 at 17:05
  • @HaoLiu: In your example the longest(0,3) is indeed 2, since you can just drop the middle two characters to get "AA" which is a palindrome of length 2. I think you have misunderstood the OP's question. – MAK Mar 07 '13 at 10:17
  • @MAK Yes, you are correct. I misunderstood the concept of substring and subsequence. I considered it as a palindromic substring problem. Thank you for your explanation. – Hao Liu Mar 07 '13 at 15:59
  • 1
    I'm not understanding how this works given say the string "GG". Wouldn't it hit the first condition and return 1? – Collin Sep 25 '14 at 18:31
  • @user2079802: That's right. That was a bug. Corrected it, thanks! – MAK Sep 25 '14 at 22:00
7

This problem can also be done as a variation of a very common problem called the LCS(Longest Common sub sequence) problem. Let the input string be represented by a character array s1[0...n-1].

1) Reverse the given sequence and store the reverse in another array say s2[0..n-1] which in essence is s1[n-1....0]

2) LCS of the given sequence s1 and reverse sequence s2 will be the longest palindromic sequence.

This solution is also a O(n^2) solution.

discoverAnkit
  • 1,141
  • 1
  • 11
  • 25
  • 4
    This is unfortunately not correct. For example, for the string ACBAC, the longest common subsequence of ACBAC and its reverse CABCA is ABC, but it is not symmetric. – uohzxela Dec 04 '14 at 09:23
  • @uohzxela ACA is also a longest common subsequence of ACBAC and its reverse CABCA and ACA is symmetric – discoverAnkit Dec 04 '14 at 09:28
  • You could add an additional step to check if the LCS is symmetric, which entails a worst case of O(n^3). – uohzxela Mar 29 '16 at 18:16
  • Every longest palindromic subsequence of X is also a longest common subsequence of X and its reverse, but the converse doesn't hold. However, one can easily modify the standard LCS dynamic-programming algorithm to return an LCS that is a palindrome (given X and its reverse). – Neal Young Oct 10 '18 at 15:23
1

It makes me a little confused that the difference between substring and subsequence.(See Ex6.8 and 6.11) According to our comprehension of subsequence, the giving example doesn't have the palindromic subsequence ACGCA. Here's my pseudo code, I'm not quite sure about the initialization ><

for i = 1 to n do
    for j = 1 to i-1 do
        L(i,j) = 0
for i = 1 to n do
    L(i,i) = 1
for i = n-1 to 1 do    //pay attention to the order when filling the table
    for j = i+1 to n do
        if x[i] = x[j] then
           L(i,j) = 2 + L(i+1, j-1)
        else do
           L(i,j) = max{L(i+1, j), L(i, j-1)}
return max L(i,j)

preparing for the algorithm final...

rararabbit
  • 11
  • 2
0

Working Java Implementation of Longest Palindrome Sequence

public class LongestPalindrome 
{
    int max(int x , int y)
    {
        return (x>y)? x:y;  
    }

    int lps(char[] a ,int i , int j)
    {
        if(i==j) //If only 1 letter
        {
            return 1;
        }
        if(a[i] == a[j] && (i+1) == j) // if there are 2 character and both are equal
        {
            return 2;   
        }
        if(a[i] == a[j]) // If first and last char are equal
        {
            return lps(a , i+1 , j-1) +2;
        }
        return max(lps(a,i+1 ,j),lps(a,i,j-1)); 
    }

    public static void main(String[] args) 
    {
        String s = "NAMAN IS NAMAN";
        LongestPalindrome p = new LongestPalindrome();
        char[] c = s.toCharArray();
        System.out.print("Length of longest seq is" + p.lps(c,0,c.length-1));           
    }
}
Todd
  • 30,472
  • 11
  • 81
  • 89
  • is this solution dynamic programming solution? Sorry but i can not understand the concepts of dynamic programmings. And this solutions' complexity is O(n^2)? – Ömer Faruk AK Apr 28 '13 at 12:24
  • Yes this is dynamic programming approach.This is the simple implementation of the solution provided above.I am not sure about about complexity.You can also make the memoized version of this solution because this problem has overlapping sub problems. – user2159588 Apr 30 '13 at 04:44
  • Does not work with input = "forgeeksskeegfor" - wrongly said length is: 12, where as it should be 10 ("geeksskeeg"). – javauser71 Aug 10 '13 at 17:50
  • 7
    I've got a couple of points to make: 1) this is not dynamic programming, but naive recursion with an exponential time complexity and 2)@javauser71: 12 is the correct result, the palindrome is any of the following: "fgeeksskeegf", "ogeeksskeego" or "rgeeksskeegr". Bear in mind that a subsequence is not necessarily contiguous! – micantox Nov 16 '13 at 16:54
0

import java.util.HashSet;

import java.util.Scanner;

/** * @param args * We are given a string and we need to find the longest subsequence in that string which is palindrome * In this code we have used hashset in order to determine the unique set of substring in the given strings */

public class NumberOfPalindrome {

    /**
     * @param args
     * Given a string find the longest possible substring which is a palindrome.
     */
    public static HashSet<String> h = new HashSet<>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        for(int i=0;i<=s.length()/2;i++)
            h.add(s.charAt(i)+"");
        longestPalindrome(s.substring(0, (s.length()/2)+(s.length()%2)));
        System.out.println(h.size()+s.length()/2);
        System.out.print(h);
    }

    public static void longestPalindrome(String s){
        //System.out.println(s);
        if(s.length()==0 || s.length()==1)
            return;
        if(checkPalindrome(s)){
            h.add(s);
        }
        longestPalindrome(s.substring(0, s.length()-1));
        longestPalindrome(s.substring(1, s.length()));

    }
    public static boolean checkPalindrome(String s){
        //System.out.println(s);
        int i=0;int j=s.length()-1;
        while(i<=j){
            if(s.charAt(i)!=s.charAt(j))
                return false;
            i++;j--;
        }
        return true;
    }
}
0
private static int findLongestPalindromicSubsequence(String string) { 
    int stringLength = string.length();
    int[][] l = new int[stringLength][stringLength];
    for(int length = 1; length<= stringLength; length++){
        for(int left = 0;left<= stringLength - length;left++){
            int right = left+ length -1;
            if(length == 1){
                l[left][right] = 1;
            }
            else{  
                if(string.charAt(left) == string.charAt(right)){
                    //L(0, n-1) = L(1, n-2) + 2
                    if(length == 2){
                        // aa
                        l[left][right] = 2;
                    }
                    else{
                        l[left][right] = l[left+1][right-1]+2;
                    } 
                }
                else{
                    //L(0, n-1) = MAX ( L(1, n-1) ,  L(0, n-2) )
                    l[left][right] = (l[left+1][right] > l[left][right-1])?l[left+1][right] : l[left][right-1];
                } 
            }  
        }
    } 
    return l[0][stringLength-1];
}
John
  • 791
  • 2
  • 7
  • 25
0

Program to find the longest palindrome substring from a given string.

package source;
        
        import java.util.ArrayList;
                
        public class LongestPalindrome 
        {
            //Check the given string is palindrome by 
            public static boolean isPalindrome (String s)
            {
                StringBuffer sb = new StringBuffer(s);
                if(s.equalsIgnoreCase(sb.reverse().toString()))
                    return true;
                else
                    return false;
            }
        
            public static void main(String[] args) 
            {
                //String / word without space
                String str = "MOMABCMOMOM"; // "mom" //"abccbabcd"
                
                if(str.length() > 2 )
                {
                    StringBuffer sb = new StringBuffer();
                    ArrayList<String> allPalindromeList = new ArrayList<>();
                            
                    for(int i=0; i<str.length(); i++)
                    {
                        for(int j=i; j<str.length(); j++)
                        {
                            sb.append(str.charAt(j));
                            if( isPalindrome(sb.toString()) ) {
                                allPalindromeList.add(sb.toString());                       
                            }
                        }
                        //clear the stringBuffer
                        sb.delete(0, sb.length());
                    }
                     
                    int maxSubStrLength = -1;
                    int indexMaxSubStr = -1;
                    int index = -1;
                    
                    for (String subStr : allPalindromeList) {
                        ++index;
                        if(maxSubStrLength < subStr.length()) {
                            maxSubStrLength = subStr.length();
                            indexMaxSubStr = index;
                        }
                    }
                    if(maxSubStrLength > 2)
                        System.out.println("Maximum Length Palindrome SubString is : "+allPalindromeList.get(indexMaxSubStr));
                    else
                        System.out.println("Not able to find a Palindrome who is three character in length!!");
                
                }
            }
        
        }
Avinash Pande
  • 1,510
  • 19
  • 17
-1

for each letter in the string:

  • set the letter as the middle of the palindrome (current Length = 1)

  • check how long would be the palindrome if this is its middle

  • if this palindrome is longer than the one we found (until now) : keep the index and the size of the palindrome.

O(N^2) : since we have one loop that choose the middle and one loop that check how long the palindrome if this is the middle. each loop runs from 0 to O(N) [the first one from 0 to N-1 and the second one is from 0 to (N-1)/2]

for example: D B A B C B A

i=0 : D is the middle of the palindrome, can't be longer than 1 (since it's the first one)

i=1: B is the middle of the palindrome, check char before and after B : not identical (D in one side and A in the other) --> length is 1.

i=2 : A is middle of the palindrome, check char before and after A : both B --> length is 3. check chars with gap of 2: not identiacl (D in one side and C in the other) --> length is 3.

etc.

SivGo
  • 226
  • 1
  • 2
  • 3
    The question asks for longest palindromic subsequence, not substring. This means that the letters in the string you take do not need to be contiguous. – Nabb Jan 25 '11 at 06:52
-2

Input : A1,A2,....,An

Goal : Find the longest strictly increasing subsequence (not necessarily contiguous)​.

L(j): Longest strictly increasing subsequence ending at j

L(j): max{ L(i)}+1 } where i < j and A[i] < A[j]

Then find max{ L(j) } for all j

You will get the source code here

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • 8
    Welcome, and thanks for answering. In future though, it's worth including details of the code (not just linking to an external resource). Also, the green tick by the topmost answer indicates that this question already has an accepted answer. Try to answer questions that haven't had so much attention already - your contribution there will be more greatly valued. – Dan Puzey Dec 05 '12 at 18:04