Algorithm 如何找到最长的回文子序列(不是其长度)
我想找出字符串中最长的回文子序列。无论在哪里,我都能找到算法来计算子序列的长度,并声明该算法也可以扩展以返回子序列,但我还没有找到方法。有人能解释一下如何获得序列吗?在动态编程表中为每个单元格保留一个反向指针和一个值。然后按照表末尾的回溯来重建子序列。技巧的工作原理如下:Algorithm 如何找到最长的回文子序列(不是其长度),algorithm,dynamic-programming,Algorithm,Dynamic Programming,我想找出字符串中最长的回文子序列。无论在哪里,我都能找到算法来计算子序列的长度,并声明该算法也可以扩展以返回子序列,但我还没有找到方法。有人能解释一下如何获得序列吗?在动态编程表中为每个单元格保留一个反向指针和一个值。然后按照表末尾的回溯来重建子序列。技巧的工作原理如下: int lps(char *str) { int n = strlen(str); int i, j, cl; int L[n][n]; for (i = 0; i < n; i++)
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;
}
}
- 将字符串的反面保存在临时缓冲区中
- 使用查找LCS
请注意,根据第二个字符串的定义,两个字符串的LCS也是最长的回文。由于您在Geeksforgeks中提到了链接,我修改了解决方案以输出结果。我认为我们需要一个辅助的二维数组来存储回文子序列是如何产生的,这样我们最终可以通过辅助数组得到结果。您可以在下面的代码中看到逻辑:
#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;
}
#包括
#包括
使用名称空间std;
//求两个整数最大值的实用函数
intmax(intx,inty){return(x>y)?x:y;}
//返回seq中最长回文子序列的长度
整数lps(字符*str,字符*结果)
{
int n=strlen(str);
int i,j,cl;
int L[n][n];//创建一个表来存储子问题的结果
int-Way[n][n];//存储回文的来源。
//长度为1的字符串是lentgh 1的回文
对于(i=0;i 对于(cl=2;cl而言,以下溶液非常简单,不需要额外使用任何其他基质。
在这里,我们只是追溯我们的路径来生成最长的回文子序列
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;
}
}
intlps(char*str)
{
int n=strlen(str);
int i,j,cl;
国际法[n][n];
对于(i=0;i 对于(cl=2;cl一种Java方法。从计算回文子序列长度时生成的LPS矩阵构建字符串。
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]);
}
private static void LongestPalindromicSubsequence(char a[])
{
int len=a.长度;
int lps[][]=新的int[len][len];
int l=1;
for(int i=0;长度为1的字符串的子序列的i长度为1=mid)
{
str[i++]=str[j--];
}
}
对于(i=0;i一个示例java实现。请随意发表评论
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));
}
}
公共类最长回文{
公共静态void main(字符串…参数){
最终字符串content=“GOBANANAS”;
字符串回文组=getLongestPalindrome(内容);
System.out.println(回文);
}
私有静态字符串getLongestPalindrome(最终字符串内容){
字符串lastPalindrome=“”;
对于(int lastIndex=content.length();lastIndex>=0;lastIndex--){
对于(int i=0;i lastPalindrome.length()&&part.length()>1){
布尔值isPalindrome=isPalindrome(部分);
if(isPalindrome){
最后一个回文=部分;
System.out.println(String.format(“%s:%s”,part,isAlindrome));
}
}
}
}
返回最后一个回文;
}
私有静态布尔值isAlindrome(字符串){
字符串反向=(新的StringBuilder(字符串)).reverse().toString();
返回(string.equals(reverse));
}
}
粘贴用于获取长度的算法将有助于当前的算法。这是常用的算法。这并不总是正确的:例如,ABCAB
反向是BACBA
,而ACA
是回文,ACB
也是最长的LCS,而不是回文。格罗:请澄清。ABCAB和ABCAB都不是BACBA也不包含ACA或ACB。我的方法将产生任何字母A、B或C作为解决方案(因为ABCAB不包含长度>=2的回文)Philip:我想我们讨论的是子序列而不是子字符串。srbh.kmr:啊,明白了!对不起,我不是英语母语人士。你能解释一下逻辑吗?当回文长度为奇数时,这不起作用。假设获得的回文子序列是“acbca”,在这种情况下,b不打印。当回文长度为奇数时,这不起作用。假设字符串为“acbdca”,获得的回文子序列应为“acbca”,在这种情况下,b不打印。@Satish,我在我的计算机中尝试过这一点,它可以工作。当输入为“AABCDEBAZ”时,这不起作用。输出为“AABCDCBAA”,长度为9