最长公共子序列

来源:互联网 发布:汉诺塔递归算法解析 编辑:程序博客网 时间:2024/05/22 15:35

题目描述

给你俩个字符串,找公共最长的子序列串。

分析

根据第一个串的长度M,第二个串的长度N,建立一个MXN的二维表。
这个表 dp [i][j] ,代表 第一个串从 0 ~ i号下标和第二个串从0~j号下标这俩个字串的最长公共子序列。
那么这个表的初始状态是,dp[0][0]~dp[M-1][0]的值为,如果第一个串的 i 号元素跟第二个串的0号元素相等则值为1否则值为0,但是如果dp[i-1][0]的值为1,那么dp[i][0]的值也为1。因为i-1 是 i的字串,所以 i-1 有的公共字符在i中也一定有。对于dp[0][0]~dp[0][N-1]这个初始化跟上面这个类似。
那么dp[i][j]的公式是这样的,如果dp[i][j]可能有三种情况而来:
1.dp[i-1][j]来
2.dp[i][j-1]来
3.dp[i-1][j-1]来
那么就很简单了,分析下,dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]它们三个都相差一个字符,其中dp[i-1][j-1]又是它们俩个的子序列。那么它们的三个值如果相差最多差值为1。就在于这三个序列,一个新增了一个s1串的字符,一个新增了s2串的一个字符,一个没有新增。
那么新增s1串的字符的子序列,可能因为新增后又有一个公共子序列字符,那么dp[i][j]应该选它。新增s2串的字符的子序列同理。
那么可能,前面俩个新增后都没有多公共子序列字符,那么可能是第i个字符与第j个字符相等导致多了一个公共子序列的字符,那么这个时候dp[i][j]的值,就应该等于没有新增字符的dp[i-1][j-1]的值加1了。
用代码的思路就是,先从dp[i-1][j]与dp[i][j-1]中选个最大的,然后如果s1[i]==s2[j]的话,看dp[i-1][j-1]+1的值是否大于刚更新过的dp[i][j],如果大于重新更新下就Ok。

代码

#include<iostream>#include<vector>#include<string>using namespace std;void Getdp(std::string&s1 ,std::string&s2,vector<vector<int>>&ret){    int m  = s1.size();    int n = s2.size();    for(int i=0;i<m;++i)    {       ret[i][0]=((s1[i]==s2[0]||(i>0&&ret[i][0]==1)))?1:0;    }    for(int i=0;i<n;++i)    {       ret[0][i]=((s2[i]==s1[0]||(i>0&&ret[0][i]==1)))?1:0;    }    for(int i=1;i<m;++i)    {        for(int j=1;j<n;++j)         {            ret[i][j]=(ret[i-1][j]>ret[i][j-1])?ret[i-1][j]:ret[i][j-1];            if(s1[i]==s2[j]&&ret[i-1][j-1]+1>ret[i][j])                ret[i][j]=ret[i-1][j-1]+1;        }    }}std::string GetSub(std::string & s1 ,std::string & s2 ){    vector<vector<int>> dp(s1.size());    for(auto&i:dp)    {        i.resize(s2.size());    }    Getdp(s1,s2,dp);    int m =s1.size();    int n =s2.size();        std::string ret;    ret.resize(dp[m-1][n-1]);    int count = ret.size()-1;    int Row = m-1;    int Col = n-1;    while(count>=0)    {       if(Row>0&&dp[Row-1][Col]==dp[Row][Col])           --Row;       else if(Col>0&&dp[Row][Col-1]==dp[Row][Col])           --Col;       else       {          ret[count--]=s1[Row];          --Row,--Col;       }    }    return ret;}int main(){     std::string s1 = "1A2C3D4B56";     std::string s2 = "B1D23CA45B6A";     std::string ret=GetSub(s1,s2);     std::cout<<ret<<std::endl;     return 0;}
原创粉丝点击