经典dp 最长公共子序列

Posted 可是我不配

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了经典dp 最长公共子序列相关的知识,希望对你有一定的参考价值。

首先,说明一下子序列的定义……

一个序列A={a1,a2,a3,...,an},从中删除任意若干项,剩余的序列叫A的一个子序列。

很明显(并不明显……),子序列……并不需要元素是连续的……(一开始的时候思维总是以为元素是连续的,好傻啊……)

然后是公共子序列……

如果C是A的子序列,也是B的子序列,那么C是A和B的公共子序列……

公共子序列一般不止一个,最长的那个就是最长公共子序列,当然也可能不止一个……

煮个栗子……

A={1,3,6,9,5,4,8,7},B={1,6,3,4,5,7}

{1,4,7}是A和B的公共子序列

{1,3,4,7}是A和B的最长公共子序列

好了,说明的部分就到这,接下来,进入解决问题的部分……

给出序列A={a1,a2,a3...an},B={b1,b2,b3...bn}

我们用lcs[i][j]来表示A的前i项和B的前j项的最长公共子序列的长度

flag[i][j]表示这一点是由哪点继承来的,然后,开始搜索……

如果……

(1)A[i]==B[j]

那么就代表lcs[i][j]的最后一项一定是A[i],就是在lcs[i-1][j-1]接上A[i],也就是lcs[i][j]=lcs[i-1][j-1]+1,并记录flag[i][j]

(2)A[i]!=B[j]

那么lcs[i][j]=max(lcs[i-1][j-1],lcs[i][j-1]),因为既然接不上,那就继承一个长一点的留着呗,不要忘记了flag[i][j]的数字是不同的亲~

可能我说的比较简略,上一张比较好理解的图……

可能第一次看会很凌乱,仔细看吧亲……

最后按flag打出来就好了~

最后上代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 int lcs[1005][1005];
 4 int flag[1005][1005];
 5 char a[1005],b[1005];
 6 void findlcs(char a[],char b[],int lena,int lenb){
 7     int i,j;
 8     for(i=1;i<=lena;i++)
 9         for(j=1;j<=lenb;j++){
10             if(a[i-1]==b[j-1]){
11                 lcs[i][j]=lcs[i-1][j-1]+1;
12                 flag[i][j]=1;
13             }
14             else{
15                 if(lcs[i][j-1]>lcs[i-1][j]){
16                     lcs[i][j]=lcs[i][j-1];
17                     flag[i][j]=2;
18                 }
19                 else{
20                     lcs[i][j]=lcs[i-1][j];
21                     flag[i][j]=3;
22                 }
23             }
24         }
25 }
26 void printlcs(char a[],char b[],int lena,int lenb){
27     int i=lena;
28     int j=lenb;
29     int len=0;
30     int rec[1050];
31     while(i>0&&j>0){
32         if(flag[i][j]==1){
33             rec[len++]=a[i-1];
34             i--,j--;
35         }
36         else if(flag[i][j]==2) j--;
37         else if(flag[i][j]==3) i--;
38     }
39     len--;
40     while(len>=0){
41         printf("%c",rec[len--]);
42     }
43     printf("\\n");
44 }
45 int main(){
46     while(~scanf("%s%s",a,b)){
47         int lena=strlen(a);
48         int lenb=strlen(b);
49         findlcs(a,b,lena,lenb);
50         printlcs(a,b,lena,lenb);
51         memset(flag,0,sizeof(flag));
52         memset(lcs,0,sizeof(lcs));
53     }
54     return 0;
55 }
View Code

 

以上是关于经典dp 最长公共子序列的主要内容,如果未能解决你的问题,请参考以下文章

经典题--最长公共子序列(LCS)

最长公共子序列及其引申问题

最长公共子序列-golang

LeetCode 1143 最长公共子序列

一天一道算法题---最长公共子序列

897. 最长公共子序列