最长回文子序列

来源:互联网 发布:时间费用优化 编辑:程序博客网 时间:2024/05/16 15:22

问题描述:

给一个字符串,找出它的最长的回文子序列的长度。

例如,如果给定的序列是“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的长度

0 0