📜  最长回文序列

📅  最后修改于: 2020-12-10 06:38:08             🧑  作者: Mango

最长回文序列

它是在一个字符串的字符可以拼写和阅读同样的两种方式,向前和向后的顺序。诸如思域,雷迪维德,神化,雷达,水平,夫人,转子,参考,皮划艇,赛车和复活器之类的词。但是在回文性子序列中,序列可以但不一定以相同的相对顺序出现,但是本质上必然是连续的和回文性的机会可以忽略不计。

动态编程解决方案-

示例-给我们一个序列“ BDBADBDCBDCADB”。那么最长的回文将是11-“ BDABDCDBADB”,这是这里最长的回文序列。 “ BBABB”,“ DAD”,“ BBDBB”等也是给定序列的回文序列,但它们并不是最长的。用简单的话来说,序列会产生子序列,然后我们比较它们的长度,找出哪个回文子序列最长。

我们遵循以下步骤,使用动态编程解决方案来实现最扩展的回文序列-

首先,我们颠倒顺序。

然后,我们使用LCS算法(最长公共子序列)在原始序列和反向序列之间找到最长的公共子序列。在这里,原始LCS和反向LCS是一个返回字符串对之间最长公共子序列的函数,现在,来自LCS的答案将是最长回文子序列。

令LP(a,b)=数组Z中从索引a到b的最长回文子序列的长度

LP(a,b)= LP(a + 1,b-1)+ 2:如果Z [a] = X [b]

= max [LP(a + 1,b),LP(a,b-1)]:如果Z [a]! = Z [b]

如果a = b = 1

如果a = b-1和Z [a] = 1。 = Z [b]

= 2,如果a = b-1并且Z [a] = Z [b]

代码-

#include
using namespace std;
int max (int a, int b) {  return (a > b)? a : b;
}
int palSubseqLen(string str) {
   int n = str.size();
   int lenTable[n][n];
   for (int i = 0; i < n; i++)
      lenTable[i][i] = 1;
   for (int col=2; col<=n; col++) {      for (int i=0; i

输出-

最长回文序列的长度为:11

现在,如果我们将以上所有情况组合成一个数学方程式:

我们将原始序列称为X =(x1x2 … xm),取反为Y =(y1y2 … ym)。在此,X的前缀是X1、2、3 … m,Y的前缀是Y1、2、3 … m。

令LCS(XI,Yj)代表前缀Xi和Yj的最长公共子序列集。

然后:

LCS(Xi,Yj)=∅;如果i = 0或j = 0

LCS(Xi,Yj)= LCS(Xi-1,Yj-1)^ xi;如果i> 0,j> 0&xi = yj

LCS(Xi,Yj)= max {LCS(Xi,Yj-1),LCS(Xi-1,Yj)};如果i> 0,j> 0&xi≠yj

如果最后一个字符匹配,则序列LCS(Xi-1,Yj-1)被该匹配字符xi扩展。否则,将使用LCS(Xi,Yj-1)和LCS(Xi-1,Yj)的最佳结果。

在递归方法中,我们计算一些子问题,将其划分,然后重复执行此类任务。因此,这是一种简单但非常乏味的方法。递归解决方案中的时间复杂度更高。最坏情况下的时间复杂度是指数O(2 ^ n),程序使用的辅助空间是O(1)。

在X中,如果最后一个字符和第一个字符相同-

X(0,n-1)= X(1,n-2)+ 2

如果没有的话

X(0,n-1)= MAX(X(1,n-1),X(0,n-2))。

代码-

(在爪哇)

class Main
{
public static String longestPalindrome(String X, String Y, int m, int n, int[][] T)
{
if (m == 0 || n == 0) {
return "";
}
if (X.charAt(m - 1) == Y.charAt(n - 1))
{
return longestPalindrome(X, Y, m - 1, n - 1, T) + X.charAt(m - 1);
}
if (T[m - 1][n] > T[m][n - 1]) {
return longestPalindrome(X, Y, m - 1, n, T);
}
return longestPalindrome(X, Y, m, n - 1, T);
}
public static int LCSLength(String X, String Y, int n, int[][] T)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (X.charAt(i - 1) == Y.charAt(j - 1)) 
{
T[i][j] = T[i - 1][j - 1] + 1;
}
else 
{
T[i][j] = Integer.max(T[i - 1][j], T[i][j - 1]);
}
}
}
return T[n][n];
}
public static void main(String[] args)
{
String X = "BDBADBDCBDCADB";
String Y = new StringBuilder(X).reverse().toString();
int[][] T = new int[X.length() + 1][X.length() + 1];
System.out.println("The length of Longest Palindromic Subsequence is "
                        + LCSLength(X, Y, X.length(), T));
System.out.println("The Longest Palindromic Subsequence is "
                        + longestPalindrome(X, Y, X.length(), X.length(), T));
}
}

输出-

最长回文序列的长度为11

最长的回文序列是BDADBCBDADB

现在,如果我们将以上所有情况组合成一个数学方程式:

我们将原始序列称为X =(x1x2 … xm),取反为Y =(y1y2 … ym)。在此,X的前缀是X1、2、3 … m,Y的前缀是Y1、2、3 … m。

令LCS(XI,Yj)代表前缀Xi和Yj的最长公共子序列集。

然后:

LCS(Xi,Yj)=∅;如果i = 0或j = 0

LCS(Xi,Yj)= LCS(Xi-1,Yj-1)^ xi;如果i> 0,j> 0&xi = yj

LCS(Xi,Yj)= max {LCS(Xi,Yj-1),LCS(Xi-1,Yj)};如果i> 0,j> 0&xi≠yj

如果最后一个字符匹配,则序列LCS(Xi-1,Yj-1)被该匹配字符xi扩展。否则,将使用LCS(Xi,Yj-1)和LCS(Xi-1,Yj)的最佳结果。

在递归方法中,我们计算一些子问题,将其划分,然后重复执行此类任务。因此,这是一种简单但非常乏味的方法。递归解决方案中的时间复杂度更高。最坏情况下的时间复杂度是指数O(2 ^ n),程序使用的辅助空间是O(1)。

在X中,如果最后一个字符和第一个字符相同-

X(0,n-1)= X(1,n-2)+ 2

如果没有的话

X(0,n-1)= MAX(X(1,n-1),X(0,n-2))。

代码-

(在爪哇)

class Main
{
public static String longestPalindrome(String X, String Y, int m, int n, int[][] T)
{
if (m == 0 || n == 0) {
return "";
}
if (X.charAt(m - 1) == Y.charAt(n - 1))
{
return longestPalindrome(X, Y, m - 1, n - 1, T) + X.charAt(m - 1);
}
if (T[m - 1][n] > T[m][n - 1]) {
return longestPalindrome(X, Y, m - 1, n, T);
}
return longestPalindrome(X, Y, m, n - 1, T);
}
public static int LCSLength(String X, String Y, int n, int[][] T)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (X.charAt(i - 1) == Y.charAt(j - 1)) 
{
T[i][j] = T[i - 1][j - 1] + 1;
}
else 
{
T[i][j] = Integer.max(T[i - 1][j], T[i][j - 1]);
}
}
}
return T[n][n];
}
public static void main(String[] args)
{
String X = "BDBADBDCBDCADB";
String Y = new StringBuilder(X).reverse().toString();
int[][] T = new int[X.length() + 1][X.length() + 1];
System.out.println("The length of Longest Palindromic Subsequence is "
                        + LCSLength(X, Y, X.length(), T));
System.out.println("The Longest Palindromic Subsequence is "
                        + longestPalindrome(X, Y, X.length(), X.length(), T));
}
}

输出-

最长回文序列的长度为11

最长的回文序列是BDADBCBDADB

最佳子结构-

它满足重叠的子问题属性。在二维数组中,最长公共子序列可以作为备忘,其中LCS [X] [Y]表示长度为X的原件与长度为Reverse的长度之间的长度。填充并使用上述算法后,可以通过回溯技术生成最长回文子序列