给一个字符串,找出它的最长的回文子序列的长度。
回文序列(Palindromic sequence, Palindrome)是指正向遍历和反向遍历完全相同的序列,例如,如果给定的序列是“BBABCBCAB”,则输出应该是7,“BABCBAB”是在它的最长回文子序列。“BBBBB”和“BBCBB”也都是该字符串的回文子序列,但不是最长的。
//腾讯2016笔试一。对于一个输入字符串,求删除几个字符后,剩下的可以成为回文字符。
//最长公共子串字符求法:动态规划
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int LongCommonStr(string s)
{
string sr(s);
reverse(sr.begin(),sr.end());
int n=s.size();
int p[n+1][n+1];
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(s[i-1]==sr[j-1])
p[i][j]=p[i-1][j-1]+1;
else
p[i][j]=p[i][j-1]>p[i-1][j]?p[i][j-1]:p[i-1][j];
}
}
return p[n][n];
}
int main()
{
string str;
while(cin>>str)
{
int lcs=LongCommonStr(str);
cout<<str.size()-lcs<<endl;
}
return 0;
}
类似 最长公共子序列LCS( Longest Common Subsequence)问题,可以是不连续的。这就是 LPS(Longest Palindromic Subsequence)问题。
注意:和最长回文子串的区别(参考:最长回文串)!这里说的子序列,
最直接的解决方法是:生成给定字符串的所有子序列,并找出最长的回文序列,这个方法的复杂度是指数级的。
其实这个问题和最长公共子序列问题有些相似之处,我们可以对LCS算法做些修改,来解决此问题:
1) 对给定的字符串S逆序 存储在另一个数组 Srev中。
2) 再求这两个字符串的 LCS的长度。
时间复杂度为 O(n^2),空间复杂度为O(n^2)。
下面来分析用动态规划解决。通过自下而上的方式打表,存储子问题的最优解。
设输入字符串为S,长度为n,Srev为字符串S的逆序。则LPS(S)=LCS(S,Srev).
参考LCS的思路进行求解:建立一个二维表格,大小为dp[n+1][n+1],二维数组的第0行和第0列值为0,表示公共字符为0.
当S[i-1]==Srev[j-1]时,dp[i][j]=dp[i-1][j-1]+1; 否则,dp[i][j]=max(dp[i-1][j],dp[i][j-1])。
则LPS=dp[n][n]。(二维数组的最右下角)