最长回文子序列

问题描述:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值