[算法]求最长公共子序列

最长公共子序列:一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。子序列不要求是连续的,但要求前后的相对顺序一致!

使用DP动态规划方法,算法时间、空间复杂度为O(m*n)。

递推公式:
recursive formula
既然涉及到公共子序列,也就是有X的第 i 个字符和Y的第 j 个字符相等的情况。
显然如果X[i] = Y[j] 那么长度分别为 i 和 j 的最长公共子序列就是长度分别为 i-1 和 j-1的最长公共子序列 加上 X[i] 或 Y[j]。
如果X[i] != Y[j] 呢?
如果不相等,那么长度为 i 和长度为 j 的序列的最长公共子序列就是“长度为i-1 和 j ” 和“长度为 i 和 j-1 ”中最长公共子序列中较长的一个。

我的程序:
int max(int a,int b)
{
    return a>b?a:b;
}

int main()
{
    char a[100],b[100];

    while(cin>>a>>b)
    {


    int na=strlen(a);
    int nb=strlen(b);

    int len[100][100];
    memset(len,0,sizeof(len));


    for(int i=0;i<na;++i)
    {
        for(int j=0;j<nb;++j)
        {
            if(i==0 || j==0)//ij为0时必须小心处理。如果只考虑a[i]==b[j]情况,当不相等时,就会调用max(a[i-1],b[j-1])就越界了。
            {
                if(a[i]==b[j])
                {
                    len[i][j]=1;
                }
                else if(i==0 && j!=0)
                {
                    len[i][j]=len[i][j-1];
                }
                else if(i!=0 && j==0)
                {
                    len[i][j]=len[i-1][j];
                }
                else if(i==0 && j==0)
                {
                    len[i][j]=0;
                }

            }
            else if(a[i]==b[j])
            {
                len[i][j]=len[i-1][j-1]+1;
            }
            else
            {
                len[i][j]=max(len[i-1][j],len[i][j-1]);
            }
        }
    }
    cout<<len[na-1][nb-1]<<endl;

    }
    return 0;
}

最大子串的输出:
flow
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m + n)。
int i=na-1,j=nb-1,count=len[na-1][nb-1];
        while(count!=0)
        {
            if(a[i]==b[j])
            {
                cout<<a[i]<<" ";
                i--;
                j--;
                count--;
            }
            else if(len[i][j-1]>len[i-1][j])
            {
                j--;
            }
            else
            {
                i--;
            }
        }cout<<endl;

从最后开始,碰到一样的输出,不一样的,往更大的方向跑。其实就是前面生成len的逆过程。
原文地址:https://www.cnblogs.com/iyjhabc/p/2987475.html