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

Algorithm 如何找到最长回文子序列?,algorithm,dynamic-programming,palindrome,Algorithm,Dynamic Programming,Palindrome,这里是算法书(Vazirani)中的问题(6.7),与经典问题略有不同。我怎样才能解决这个问题 如果子序列是回文序列,则该子序列是回文序列 无论从左向右还是从左向右读取,都相同 从右到左。例如 序列 A,C,G,T,G,T,C,A,A,A,A,T,C,G 有许多回文子序列, 包括A,C,G,C,A和A,A,A (另一方面,子序列 A,C,T不是回文)。设计 采用序列x[1]的算法 …n]并返回(长度) 最长回文子序列。它的 运行时间应为O(n^2) 对于字符串中的每个字母: 将字母设置为回文

这里是算法书(Vazirani)中的问题(6.7),与经典问题略有不同。我怎样才能解决这个问题

如果子序列是回文序列,则该子序列是回文序列 无论从左向右还是从左向右读取,都相同 从右到左。例如 序列

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


对于字符串中的每个字母:

  • 将字母设置为回文的中间部分(当前长度=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:not-idential前后的字符(一边是D,另一边是A)-->长度是1

i=2:A是回文的中间部分,检查A:B-->长度为3前后的字符。检查间隙为2的字符:不一致(一侧为D,另一侧为C)->长度为3

等等。

这可以用动态规划在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

最长(i,j)=j-i+1,如果j-i输入:A1,A2,…,An

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

L(j):最长严格递增子序列,以j结尾

L(j):
max{L(i)}+1},其中i

然后为所有j查找
max{L(j)}


您将获得最长回文序列的源代码

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

子串和子序列之间的区别让我有点困惑。(参见Ex6.8和6.11)根据我们对子序列的理解,给出的示例没有回文子序列ACGCA。
这是我的伪代码,我不太确定初始化>这个问题也可以作为一个非常常见的问题LCS(最长公共子序列)问题的变体来解决。 让输入字符串由字符数组s1[0…n-1]表示

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

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


此溶液也是O(n^2)溶液

导入java.util.HashSet

导入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;
    }
}
/**
*@param args
*给定一个字符串,找到可能最长的子字符串,即回文。
*/
公共静态HashSet h=新HashSet();
公共静态void main(字符串[]args){
扫描仪sc=新的扫描仪(System.in);
字符串s=sc.nextLine();
对于(int i=0;i
private static int findLongestPalindromicSubsequence(String字符串){
int stringLength=string.length();
int[][]l=新int[stringLength][stringLength];

用于(int-length=1;length程序从给定字符串中查找最长回文子字符串。

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!!");
                
                }
            }
        
        }
包源;
导入java.util.ArrayList;
公共类最长回文
{
//通过检查给定字符串是否为回文
公共静态布尔值isAlindrome(字符串s)
{
StringBuffer sb=新的StringBuffer;
如果(s.equalsIgnoreCase(sb.reverse().toString()))
返回true;
其他的
返回false;
}
公共静态void main(字符串[]args)
{
//不带空格的字符串/单词
字符串str=“momabcomom”;/“mom”//“abccbabcd”
如果(str.length()>2)
{
StringBuffer sb=新的StringBuffer();
ArrayList allPalindromeList=新建ArrayList();

对于(int i=0;这个问题要求的是最长的回文子序列,而不是子字符串。这意味着字符串中的字母不需要是连续的。我认为当它们匹配时应该是
2+…
,如果j-i这是一个O(n^2)算法,那么
j-i?n的输入不是不同的吗
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];
}
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!!");
                
                }
            }
        
        }