zoukankan      html  css  js  c++  java
  • [算法]求最长公共子序列

    最长公共子序列:一个数列 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的逆过程。
  • 相关阅读:
    数据结构与算法分析
    案例分析作业
    实验六——循环结构程序练习总结
    实验五——循环结构学习总结
    实验四——多分支结构及本章总结
    实验三——for 语句及分支结构else-if
    第二次作业及总结——数据类型和运算符
    2-c语言作业
    自然博物馆参观
    2019-2020-1学期 20192409《网络空间安全专业导论》第四周学习总结
  • 原文地址:https://www.cnblogs.com/iyjhabc/p/2987475.html
Copyright © 2011-2022 走看看