如何找到最长的回文子序列?

时间:2011-01-25 06:11:34

标签: algorithm dynamic-programming palindrome

这是来自Algorithms book(Vazirani)的问题(6.7 ch6)与finding longest palindrome的经典问题略有不同。我该如何解决这个问题?

  

如果是,则子序列是回文   无论是从左到右阅读还是   右到左。例如,   序列

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

有很多回文子句,   包括A,C,G,C,AA,A,A,A   (另一方面,子序列   A,C,T不是回文)。设计一个   采用序列x[1 ...n]并返回(长度)的算法   最长的回文序列。它的   运行时间应为O(n^2)

9 个答案:

答案 0 :(得分:77)

这可以使用动态编程在O(n ^ 2)中解决。基本上,问题是使用x[i...j]x[i+1...j]x[i,...j-1]的最长子序列在x[i+1,...,j-1]中构建最长的回文子序列(如果第一个和最后一个字母相同)。

首先,空字符串和单个字符串通常是回文。 请注意,对于子串x[i,...,j],如果x[i]==x[j],我们可以说最长回文的长度是x[i+1,...,j-1]+2以上最长的回文。如果它们不匹配,则最长的回文数是x[i+1,...,j]y[i,...,j-1]的最高回文数。

这给了我们功能:

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

你可以简单地实现该函数的memoized版本,或者编写一个最长[i] [j]自下而上的表。

这只给出了最长子序列的长度,而不是实际的子序列本身。但它也可以很容易地扩展到这样做。


答案 1 :(得分:7)

此问题也可以作为称为LCS(最长公共子序列)问题的非常常见问题的变体来完成。 让输入字符串由字符数组s1 [0 ... n-1]表示。

1)反转给定的序列并将反向存储在另一个数组中,例如s2 [0..n-1],其本质上是s1 [n-1 .... 0]

2)给定序列s1和反向序列s2的LCS将是最长的回文序列。

该解决方案也是O(n ^ 2)解决方案。

答案 2 :(得分:1)

让我有点困惑的是子串和子序列之间的差异。(见Ex6.8和6.11)根据我们对子序列的理解,给出的例子没有回文子序列ACGCA。 这是我的伪代码,我不太确定初始化&gt;&lt;

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)

准备算法最终......

答案 3 :(得分:0)

最长回文序列的Java实现

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));           
    }
}

答案 4 :(得分:0)

import java.util.HashSet;

import java.util.Scanner;

/ **  * @param args  *我们得到一个字符串,我们需要在该字符串中找到最长的子序列,即回文  *在这段代码中,我们使用了hashset来确定给定字符串中唯一的子字符串集  * /

公共类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;
    }
}

答案 5 :(得分: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];
}

答案 6 :(得分:0)

程序,用于从给定的字符串中找到最长的回文子字符串。

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!!");
                
                }
            }
        
        }

答案 7 :(得分:-1)

表示字符串中的每个字母:

  • 将字母设置为回文的中间位置(当前长度= 1)

  • 检查回文多长时间,如果这是它的中间

  • 如果这个回文比我们发现的回文长(直到现在):保持索引和回文的大小。

O(N ^ 2):因为我们有一个循环选择中间和一个循环,检查回文多长时间,如果这是中间。每个循环从0到O(N)[第一个从0到N-1,第二个从0到(N-1)/ 2]

例如: D B A B C B A

i = 0:D是回文的中间,不能超过1(因为它是第一个)

i = 1:B是回文的中间,在B之前和之后检查char:不相同(一侧为D而另一侧为A) - &gt;长度是1.

i = 2:A是回文的中间,在A之前和之后检查char:B-&gt;长度为3.检查间隙为2的字符:不识别(一边为D,另一边为C) - &gt;长度是3。

等。

答案 8 :(得分:-2)

输入: A1,A2,....,An

目标:找到最长的严格增加的子序列(不一定是连续的)。

L(j):以j结尾的最长严格增加后续序列

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

然后找max{ L(j) } for all j

您将获得源代码here