【动态规划】最长公共子序列问题

题目描述:

给定两个字符串s1s2……sn和t1t2……tn。求出这两个字符串最长的公共子序列的长度。字符串s1s2……sn的子序列指可以表示为si1si2……sim(i1<i2<……<im)的序列。(n>=1,m<=1000)

输入:

n=4

m=4

s="abcd"

t="becd"

输出:

3

分析:

阶段就是n=0,1,2,3,4……时,m=0,1,2,3……1000时;状态就是对应字符相等还是不相等。

看该题是否符合,每个阶段的最优状态可以从之前的某个阶段的某个或某些状态得到而不管之前的状态是如何得到的(最优子结构和无后效性)。

用输入输出的栗子证一下:

当n=4,m=4时,S3为‘d’,T3为‘d’,S3==T3,则此阶段对应的最长公共子序列(LCS)为n=3,m=3时的LCS加1。

当n=2,m=2时,S1为‘b‘,T1为‘e‘,S1!=T3,则此阶段对应的LCS为,n=2,m=1阶段的LCS与n=1,m=2阶段的LCS的最大值。

记忆化搜索代码:

#include <iostream>
#include <string>
#include <string.h>
#define MAX_N 1001
#define MAX_M 1001
using namespace std;
int n,m;
string s,t;
int dp[MAX_N][MAX_M];
int rec(int ni,int mi){
if(dp[ni][mi]>=0){
    return dp[ni][mi];
}
int res;
//当s和t的字符串长度为1时,它们参考的前一个LCS设为0
if(ni==0||mi==0){
    res=0;
}
else if((ni>0&&ni<=n)&&(mi>0&&mi<=m)){
    if(s[ni-1]==t[mi-1]){
        res=rec(ni-1,mi-1)+1;
    }
    else if(s[ni-1]!=t[mi-1]){
        res=max(rec(ni-1,mi),rec(ni,mi-1));
    }
}
dp[ni][mi]=res;
return res;
}
int main()
{
    cin>>n>>m;
    cin>>s>>t;
    memset(dp,-1,sizeof(dp));
    cout<<rec(n,m)<<endl;
    for(int i=0;i<=n;i++){
        for(int j=0;j<=m;j++){
            cout<<dp[i][j];
            if(j<m){
                cout<<‘ ‘;
            }
            else if(j==m){
                cout<<endl;
            }
        }
    }
    return 0;
}

根据记忆化搜索推到出递推公式,本题比较简单也可以直接写出来:

当m或n等于0,dp[n][0]=0,dp[0][m]=0;

当Si与Ti相等时,dp[n][m]=dp[n-1][m-1]+1;

当Si与Ti不相等时,dp[n][m]=max(dp[n-1][m],dp[n][m-1]);

举个不相等的栗子:

"abcdef"和"defihg",‘f‘和‘g‘不相等,则考虑"abcdef"和"defih"其LCS为3。

动态规划的代码:

#include <iostream>
#include <string>
#define MAX_N 1001
#define MAX_M 1001
using namespace std;
int dp[MAX_N][MAX_M];
int main()
{
    int n,m;
    string s,t;

    cin>>n>>m;
    cin>>s>>t;
    //递推公式中的n用i+1表示,m用j+1表示
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(s[i]==t[j]){
                dp[i+1][j+1]=dp[i][j]+1;
            }
            else if(s[i]!=t[j]){
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
            }
        }
    }
    cout<<dp[n][m]<<endl;
    return 0;
}
时间: 2024-08-07 01:34:49

【动态规划】最长公共子序列问题的相关文章

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

(1).问题描述:给出2个序列,x是从1到m,y是从1到n,找出x和y的最长公共子序列? x:A B C B D A B y:B D C A B A 则:最长公共子序列长度为4,BDAB BCAB BCBA均为LCS(最长公共子序列): 模型实现图: (2).问题解决 代码实现了最长公共子序列的长度 #include<stdio.h> #define N    10 int LCS(int *a, int count1, int *b, int count2); int LCS(int *a,

动态规划 - 最长公共子序列(LCS)

最长公共子序列也是动态规划中的一个经典问题. 有两个字符串 S1 和 S2,求一个最长公共子串,即求字符串 S3,它同时为 S1 和 S2 的子串,且要求它的长度最长,并确定这个长度.这个问题被我们称为 最长公共子序列问题. 与求最长递增子序列一样,我们首先将原问题分割成一些子问题,我们用 dp[i][j]表示 S1 中前 i 个字符与 S2 中前 j 个字符分别组成的两个前缀字符串的最 长公共子串长度. 显然的,当 i. j 较小时我们可以直接得出答案,如 dp[0][j]必 等于 0.那么,

动态规划——最长公共子序列

最长公共子序列(LCS)是一类典型的动归问题. 问题 给定两个序列(整数序列或者字符串)A和B,序列的子序列定义为从序列中按照索引单调增加的顺序取出若干个元素得到的新的序列,比如从序列A中取出 A[i1], A[i2], ...A[ik],其中0=< i1 <= i2 <= ... ik <= n-1得到的新的序列 A[i1].A[i2]....A[ik]即为A的一个子序列.     两个不同的原序列A和B可能有着相同的子序列,求出A和B的公共子序列的最长长度. 分析     这种

《算法导论》读书笔记之动态规划—最长公共子序列 &amp; 最长公共子串(LCS)

From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是

算法系列笔记6(动态规划—最长公共子序列/串lcs)

子序列要求元素顺序一致就可以了,而字串必须是连续的.如ABCBDAB与BDCABA两个字符串,最长公共子序列有BCBA.BDAB和BCAB, 而最长公共字串只有AB和BD<连续>.当然这里的求解只求一个,但通常是这样直接说求最长公共子串,子序列,准确的应该是之一. 最长公共子序列 法一:穷举法 检查字符串x所有字序列,共有2^m个,检查它是否在y字符串中出现,每个需要O(n),时间复杂度为指数级的. 法二:动态规划(DP) 将两个字符串x[1-m]和y[1-n]放在x轴和y轴方向上便得到一个二

第十五章 动态规划——最长公共子序列

1.基本概念 一个给定序列的子序列就是该给定序列中去掉零个或者多个元素的序列.形式化来讲就是:给定一个序列X={x1,x2,……,xm},另外一个序列Z={z1.z2.……,zk},如果存在X的一个严格递增小标序列<i1,i2……,ik>,使得对所有j=1,2,……k,有xij = zj,则Z是X的子序列.例如:Z={B,C,D,B}是X={A,B,C,B,D,A,B}的一个子序列,相应的小标为<2,3,5,7>.从定义可以看出子序列直接的元素不一定是相邻的. 公共子序列:给定两个

算法 动态规划 ------最长公共子序列

这篇博客是我 听完这位老师讲完课的 记录.https://www.youtube.com/watch?v=mgDUoITB24I&t=645s    还有我个人的理解,如果有错误或者有争议的地方,欢迎留言.谢谢大家~ 子序列  就是说 从原有列表中按照出现先后顺序从中选择部分 元素 组成的新的列表. 最长公共子序列的含义:  选择两个列表中公共的子序列的最大长度,这个子序列即为最长公共子序列. 用蛮力的方法求解,对于长度为 M的 列表,它所有的子序列的个数有  2^m  ,每个元素有两种情况,被

算法导论之动态规划(最长公共子序列和最优二叉查找树)

动态规划师通过组合子问题的解而解决整个问题,将问题划分成子问题,递归地求解各子问题,然后合并子问题的解而得到原问题的解.和分治算法思想一致,不同的是分治算法适合独立的子问题,而对于非独立的子问题,即各子问题中包含公共的子子问题,若采用分治法会重复求解,动态规划将子问题结果保存在一张表中,避免重复子问题重复求解. 动态规划在多值中选择一个最优解,其算法设计一般分为4个步骤:描述最优解的结构:递归定义最优解的值:按自底向上的方式计算最优解的值:由计算出的结果构造一个最优解. 1)装配线调度 求解最快

动态规划3-最长公共子序列问题

一些概念: (1)子序列: 一个序列A = a1,a2,……an,中任意删除若干项,剩余的序列叫做A的一个子序列.也可以认为是从序列A按原顺序保留任意若干项得到的序列. 例如: 对序列 1,3,5,4,2,6,8,7来说,序列3,4,8,7 是它的一个子序列.对于一个长度为n的序列,它一共有2^n 个子序列,有(2^n – 1)个非空子序列. 请注意:子序列不是子集,它和原始序列的元素顺序是相关的. (2)公共子序列 : 顾名思义,如果序列C既是序列A的子序列,同时也是序列B的子序列,则称它为序

动态规划——最长公共子序列(LCS)

最长公共子序列的问题描述为: 下面介绍动态规划的做法. 令 dp[i][j] 表示字符串 A 的 i 号位与字符串 B 的 j 号位之前的 LCS 长度(下标从 1 开始),如 dp[4][5] 表示 "sads" 与 "admin" 的 LCS 长度.那么可以根据 A[i] 和 B[j] 的情况,分为两种决策: 若 A[i]==B[j],则字符串 A 与字符串 B 的 LCS 增加了 1 位,即有 dp[i][j]=dp[i-1][j-1]+1. 若 A[i] !