动态规划9--例9.9最长公共子序列

1265:【例9.9】最长公共子序列
【题目描述】

一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
确切地说,若给定序列X=<x1,x2,…,xm>,则另一序列Z=<z1,z2,…,zk>是X的子序列
是指存在一个严格递增的下标序列<i1,i2,…,ik>,使得对于所有j=1,2,…,k有:Xij=Zj

例如,序列Z=<B,C,D,B>是序列X=<A,B,C,B,D,A,B>的子序列,相应的递增下标序列为<2,3,5,7>。
给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
例如,若X=<A,B,C,B,D,A,B>和Y=<B,D,C,A,B,A>,则序列<B,C,A>是X和Y的一个公共子序列,
序列<B,C,B,A>也是X和Y的一个公共子序列。而且,后者是X和Y的一个最长公共子序列.因为X和Y没有长度大于4的公共子序列。

给定两个序列X=<x1,x2,…,xm>和Y=<y1,y2….yn>.要求找出X和Y的一个最长公共子序列。
【输入】
共有两行。每行为一个由大写字母构成的长度不超过1000的字符串,表示序列X和Y。
【输出】
第一行为一个非负整数。表示所求得的最长公共子序列的长度。若不存在公共子序列.则输出文件仅有一行输出一个整数0。

提示:
最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common
Subsequence, LCS)的区别为:子串是串的一个连续的部分,子序列则是不改变序列的顺序,
而从序列中去掉任意的元素而获得新的序列,也就是说,子串中字符的位置必须是连续的,
子序列则可以不必连续.字符串长度小于等于1000.


算法分析:

与最长不下降子序列(LIS)类似的,我们可以以子序列的结尾作为状态,但现在有两个子序列,
那么直接以两个子序列当前的结尾作为状态即可.

①  确定状态:
设F[x][y]表示S[l..x]与T[1..y]的最长公共子序列的长度,答案为F[|S|][|T|],

②  确定状态转移方程和边界条件:
分三种情况来考虑:
•S[x]不在公共于序列中:该情况下F[x][y] = F[x-l][y],
•T[y]不在公共于序列中:该情况下F[x][y] = F[x][y-l],
-S[x] = T[y],S[x]与 T[y]在公共子序列中:该情况下.FEx][y] = F[x-l][y-1]+ 1。
F[x][y]取上述三种情况的最大值。综上,
状态转移方程: F[x][y] = max{F[x—l][y],F[x][y—l],F[x—l][y—l] + l},其中第三种情况要満足S[x] = T[y];
边界条件:F[O][y]=O, F[x][O] = O.

③程序实现,
计算F[x][y]时用到F[x-l][y-l].F[x-l][y],FCx][y-l]这些状态,它们要么在
F[x][y]的上一行,要么在F[x][y]的左边。因此預处理出第。行,然后按照行从小到大、同一行
按照列从小到大的顺序来计算就可以用迭代法计算出来。时间复杂度为0(|S| * |T|).

借鉴网上一张图:


代码:

#include<iostream>
using namespace std;

//数据初始化

const int MAXN=5005;
string S,T;
int F[20][20];

//处理函数

//主函数
int main(){
    //初始化数据
    //输入数据
    cin>>S;
    cin>>T;
    int ls=S.length();
    int lt=T.length();

    int n=0;

    //事务处理
    for(int i=1;i<=ls;i++){
        for (int j = 1; j <=lt ; ++j) {
            F[i][j]=max(F[i-1][j],F[i][j-1]);
            n=F[i][j];
            if(S[i-1]==T[j-1]){
                F[i][j]=max(F[i][j],F[i-1][j-1]+1);
            }
        }
    }

    //输出数据
    cout<<F[ls][lt]<<endl;

    return 0;
}

总结:

1.这一题感觉有点难,代码看着比较少,但是理解起来有点抽象

2.这一题还是比较基础的一个题只要求出长度,进阶版是还要求打印出公共子序列。

参考:

https://blog.csdn.net/weixin_40673608/article/details/84262695?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值