算法学习笔记 最长公共子序列LCS

给定两个字符串,求最长公共子序列及其长度(不同于最长公共子串的是公共子串要求连续)

思路:

设字串为a,b 建立二维数组c用于打表,建立二维数组d,用于记录路径,其中c[i][j]表示的是a的前i个字符构成的字串和b的前j个字符构成的字串的最大公共字串的和,则分析题目得状态转移方程:若a[i]==b[j],有c[i][j]=1+c[i-1][j-1],记d[i][j]=0,如果a[i]!=b[j]有c[i][j]=max(c[i][j-1],c[i-1][j]),记d[i][j]=1或2(0<i<=strlen(a),0<j<=strlen(b))且对于任意i,j有边界条件c[0][j]=c[i][0]=0,两个数组遍历结束c[strlen(a)][strlen(b)]为所求的最大公共子串的长度。

接下来通过d来回溯具体的公共子串:i,j初始值为strlen(a),strlen(b),首先建立栈s用于逆序输出,由上述分析得,如d[i][j]=0,则a[i-1](或b[j-1])为最长公共子序列中的元素(-1是因为二维数组d和c下标都是以1开始的),压入栈中,若d[i][j]!=0,则以a[i],b[j]结尾的最大公共子串=以a[i-1],b[j]或a[i],b[j-1]结尾的最大公共子串,i或j自减,i或j<1时跳出循环,输出栈中元素即为所求,代码如下:

void maxlcs(char a[],char b[]){
    int c[maxn][maxn];//用于求最大子串长度
    int d[maxn][maxn];//用于回溯
    int i,j;
    for(i=0;i<=strlen(a);++i){//核心部分
        c[0][i]=0;
    }
    for(j=0;j<=strlen(b);++j){
        c[j][0]=0;
    }
    for(i=1;i<=strlen(a);++i)
        for(j=1;j<=strlen(b);++j)
    {
        if(a[i-1]==b[j-1])
            {c[i][j]=c[i-1][j-1]+1;
             d[i][j]=0;
             }
        else {
            if(c[i][j-1]>c[i-1][j])
                {c[i][j]=c[i][j-1];
                 d[i][j]=1;
                }
                else {
                    c[i][j]=c[i-1][j];
                    d[i][j]=2;
                }

        }
    }
    i=strlen(a);
    j=strlen(b);
    while(i>=1&&j>=1){
        switch(d[i][j]){
      case 0:
        s.push(a[i-1]);
        i--;
        j--;
        break;
      case 1:
        j--;
        break;
      case 2:
        i--;
        break;
          }

    }
    i=-1;

    while(!s.empty()){

        cout<<s.top()<<" ";
        s.pop();
    }
    cout<<c[strlen(a)][strlen(b)];

    }

注:1.如果只需求最大公共子序列的长度,由于c[i][j]只取决于它左边,上边和左上的元素,则i-1行之前已经不再需要,因此可以建立一个两行的数组来实现(滚动数组)

        2.如果c[i][j-1]==c[i-1][j],则最长公共子序列可能有多个,修改d的范围,d[i][j]=3时,c[i][j-1]==c[i-1][j]回溯的时候可以用dfs求出多个路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值