首页 > 代码库 > 最长回文子序列

最长回文子序列

15-2(最长回文子序列) 回文(palindrome)是正序与逆序相同的非空字符串。例如,所有长度为1的字符串,civic,racecar,aibohphobia都是回文。设计高效算法,求给定输入字符串的最长回文子序列。例如,给定输入character,算法应该返回carac.算法的运行时间是怎么样的?

解题思路:首先我们要注意的是题目要求求出最长回文子序列,而不是子串。如果是子串,比如abcdebca,该回文子串长度为1,是其中任意一个字符,而回文子序列是abcdbca(abcebca).所以求子串和子序列有一些不同。以下方法只适用求子序列,求子串方法由于题目没有要求,这里暂且不提了。(PS:有些人可能不清楚子串和子序列的区别,这是要特别注意的问题。)

具体方法:只要把原字符串逆转后和原字符串比较并且利用求最长公共子序列的方式求出的LCS即可得到最长回文子序列。也就是说 求出的LCS=最长回文子序列。

代码如下

#include <iostream>
using namespace std;
#define N 9//输入您要判断的字符串字符数
char*strReversal(char*str)
{
	for (int i=0;i<N/2;i++)
	{
		swap(str[i],str[N-i-1]);
	}
   return str;
}
char *b[N+2][N+2]={NULL};
int c[N+2][N+2]={0};
void Lcs_Length(char *x, char *y) 
{
	for (int i=0;i<N;i++)
	{
		for (int j=0;j<N;j++)
		{
			if (x[i]==y[j])
			{
				c[i+1][j+1]=c[i][j]+1;
				b[i+1][j+1]="↖";
			} 
			else
			{
				if (c[i][j+1]>=c[i+1][j])
				{
					c[i+1][j+1]=c[i][j+1];
					b[i+1][j+1]="↑";
				} 
				else
				{
					c[i+1][j+1]=c[i+1][j];
					b[i+1][j+1]="←";
				}
			}
		}
	}
}
void PRINT_LCS(char*x,int i,int j)
{
	if (i==0||j==0)
	{
		return;
	}
	if (b[i][j]=="↖")
	{
		PRINT_LCS(x,i-1,j-1);
		cout<<x[i-1]<<" ";
	}
	else
	{
		if (b[i][j]=="↑")
		{
			PRINT_LCS(x,i-1,j);
		} 
		else
		{
			PRINT_LCS(x,i,j-1);
		}
	}
}
void main()
{//为了和书中代码吻合,数组第一个位置存放空字符。
   	char x[N+1]={0};
	char y[N+1]={0};
	char c;
	cout<<"提示:输入字符串之前,根据需要设置N大小"<<endl;
    cout<<"请输入需要判断的字符串:"<<endl;
	for (int i=0;i<N;i++)
	{
		cin>>c;
		y[i]=x[i]=c;
	}
	y[i]='\0';x[i]='\0';
	strReversal(y);//反转字符串
	cout<<"x="<<x<<endl;
	cout<<"y="<<y<<endl;
	Lcs_Length(x, y);
	PRINT_LCS(x,N,N);
}

样例输出


最后总结:求LCS需要O(n2)时间,求字符串的逆转需要O(n)时间,总得来说本程序只需要O(n2)时间。这个问题还是较为简单的,仅仅是把书中例子改改即可得到所需结果。