问题描述:
给一个字符串,找出它的最长的回文子序列的长度。
例如,如果给定的序列是“BBABCBCAB”,则输出应该是7,“BABCBAB”是它的最长回文子序列。
注意和最长回文子串的区别!子序列可以是不连续的。这就是LPS(Longest Palindromic Subsequence)问题。
问题求解:
方法一:递归求解
X[0 … n-1] 表示给定序列,长度为n. L(0,n-1) 表示序列 X[0 … n-1] 的最长回文子序列的长度。
1、如果X的最后一个元素和第一个元素相同,这时:L(0, n-1) = L(1, n-2) + 2 。
2、如果不相同:L(0, n-1) = MAX ( L(1, n-1) , L(0, n-2) )。 L(1,n-1)即为去掉第一个元素的子序列,L(0, n-2)为去掉最后一个元素。
代码:
#include <iostream>
using namespace std;
int LPS(string str, int begin, int end)
{
if(begin==end) return 1;
if(begin > end) return 0;
if(str[begin] == str[end])
{//(1)首尾相同
return LPS(str, begin+1, end-1)+2;
}
//(2)首尾不同
return max(LPS(str, begin+1, end), LPS(str, begin, end-1));
}
int main()
{
string str1="BBABCBCAB"; //LPS=7 ,“BABCBAB”
int n1=str1.size();
cout<<LPS(str1, 0, n1-1)<<endl;
string str2="abcfgbda"; //LPS=5 ,“abcba”
int n2=str2.size();
cout<<LPS(str2, 0, n2-1)<<endl;
return 0;
}
方法二:动态规划。时间复杂度为O(n^2),空间复杂度为O(n^2)。
#include <iostream>
#include<vector>
using namespace std;
int DP_LPS(string str)
{
int n=str.size();
int tmp;
vector<vector<int>> dp(n,vector<int>(n,0));
for(int i=0;i<n;i++)
{//(1)一个元素的最长子序列
dp[i][i]=1;
}
//(2)对于每一个[j,j+i]子序列的lps
for(int i=1;i<n;i++)
{
tmp=0;
for(int j=0;j+i<n;j++)
{
if(str[j] == str[j+i])
{//首尾相同
tmp=dp[j+1][j+i-1] + 2;
}
else
{//首尾不同
tmp=max(dp[j+1][j+i], dp[j][j+i-1]);
}
dp[j][j+i]=tmp;//得到[j,j+i]子序列的LPS
}
}
return dp[0][n-1];
}
int main()
{
string str1="BBABCBCAB"; //LPS=7 ,“BABCBAB”
cout<<DP_LPS(str1)<<endl;
string str2="abcfgbda"; //LPS=5 ,“abcba”
cout<<DP_LPS(str2)<<endl;
return 0;
}
方法三:利用最长公共子序列(LCS)求解。时间复杂度 O(n^2)。
1) 对给定的字符串逆序,存储在另一个数组。
2) 再求这两个字符串的 LCS的长度