最长公共子序列LCS简介

算法简介

一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。

算法思想

貌似不难吧。。。动动脑筋。
运用DP的思想,对于当前枚举到的两个数a[i],b[j],如果a[i]==b[j],那么f[i][j]=f[i-1][j-1]+1,否则就取f[i-1][j]和f[i][j-1]的最大值。

可以写出状态转移方程式:

if (a[i]==b[j])
    f[i][j]=f[i-1][j-1]+1;
else
    f[i][j]=max(f[i-1][j],f[i][j-1]);

划水

模板

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000
using namespace std;
char s1[MAXN+5],s2[MAXN+5];
int f[MAXN+5][MAXN+5];
int main(){
    scanf("%s%s",s1,s2);
    int n1=strlen(s1),n2=strlen(s2);
    memset(f,0,sizeof(f));
    for (int i=1;i<=n1;i++)
        for (int j=1;j<=n2;j++)
            if (s1[i-1]==s2[j-1])
                f[i][j]=f[i-1][j-1]+1;
            else
                f[i][j]=max(f[i-1][j],f[i][j-1]);
    printf("%d\n",f[n1][n2]);
    return 0;
}

算法拓展

某些题目可能要求你求出LCS。 此时我们可以把它往回倒推,比如像这样:

int x=n,y=m,node=f[n][m];
    while (x>0&&y>0){
        if (s1[x-1]==s2[y-1]){//如果这两个相等
            x--; y--; s[node-1]=s1[x]; node--;//往回退
        }
        else//不相等就不取并调整
            if (f[x-1][y]>f[x][y-1]) x--;
            else y--;
    }

还有些可能有三个数列,这时加一维即可。

 for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            for (int k=1;k<=l;k++)
                if (s1[i-1]==s2[j-1]&&s2[j-1]==s3[k-1])
                    f[i][j][k]=f[i-1][j-1][k-1]+1;
                else
                    f[i][j][k]=max(max(f[i-1][j][k],f[i][j-1][k]),f[i][j][k-1]);

求LCS也一样:

int x=n,y=m,z=l,node=f[n][m][l];
    while (x>0&&y>0&&z>0)
        if (s1[x-1]==s2[y-1]&&s2[y-1]==s3[z-1]){
            x--; y--; z--; node--; s[node]=s1[x];
        }
        else{
            if (f[x][y][z]==f[x-1][y][z]) x--;
            if (f[x][y][z]==f[x][y-1][z]) y--;
            if (f[x][y][z]==f[x][y][z-1]) z--;
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值