1.简单的题目描述:
如两个 字符串的 BDCABA 与 ABCBDAB,求最长的公共子序列。
PS:最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续
2.解法:DP -动态规划
str1[m] =BDCABA
下标:012345
str2[m] =ABCBDAB
下标:0123 4 5 6
C[maxlen][maxlen] 来存放结果
原理:c(i,j) 表示str[i-1],str[j-1] 的LCS 长度
得到:
回溯输出最长公共子序列过程:
如何输出LCS序列:
我们可以从后往前去找: 原序列: str1[i].B D C A B A str2[j].A B C B D A B 我们这样考虑:最后的 A B,不相等,所以 LCS 存在于『B D C A B A 和 A B C B D A 』 或 『B D C A B 和 A B C B D A B』中 就是:str[6-1] != str[7-1] 如果 c[i][j-1] = c[i-1][j] 那就表明『B D C A B A 和 A B C B D A 』 或 『B D C A B 和 A B C B D A B』的 LCS 长度一样 此时 选那个都一样:
如果str[i] == str[j] 就表示 srt[i]要输出,如果 c[i][j-1] = c[i-1][j] 那就表明『B D C A B A 和 A B C B D A 』 或 『B D C A B 和 A B C B D A B』的 LCS 长度一样
此时继续往下面去找 str[i] == str[j]
构建一个数组来倒序的存放LCS
我写的算法(C):--问题1:没有解决所有LCS 的输出,只输出一个且是倒序的
/* * ===================================================================================== * * Filename: 5.c * * Description: RT * * Version: 1.0 * Created: 2014-4-27 星期日 11:19:37 * Revision: none * Compiler: gcc * * Author: Rainboy (mn), 597872644@qq.com * Company: NONE * * ===================================================================================== */ #include <stdio.h> #include <string.h> #define maxlen 200 int c[200][200]; char str1[maxlen]="BDCABA",str2[maxlen]="ABCBDAB"; char buffer[maxlen]={0}; int main (int argc, char *argv[]) { memset(c,0,sizeof(c)); int i,j; for(i=0;i<strlen(str1);i++) /* 开始DP 运算 */ for (j=0;j<strlen(str2);j++) { if(str1[i]==str2[j]) { c[i+1][j+1]=c[i][j]+1; } else if(c[i+1][j] > c[i][j+1]) c[i+1][j+1] = c[i+1][j]; else c[i+1][j+1] =c[i][j+1]; } for(j=0;j<=strlen(str2);j++){ /* 打印c[i][j] */ for (i=0;i<=strlen(str1);i++) { printf("%4d",c[i][j]); } printf(" "); } printf(" "); printf(" "); for(i=strlen(str1),j=strlen(str2);i>0 && j>0;) /* 倒序打印一个LCS */ { if(str1[i-1]==str2[j-1]) { printf("%c",str1[i-1]); i--; j--; } else if(c[i][j-1] >= c[i-1][j]) { j--; } else { i--; } } printf(" "); printf("LCS is %d ",c[strlen(str1)][strlen(str2)]); return 0; }
算法(PAS):
const maxlen = 200; var i,j:integer; c:array[0..maxlen,0..maxlen] of integer; x,y,z:string; begin x:='BDCABA'; y:='ABCBDAB'; fillchar(c,sizeof(c),0); for i:=1 to length(x) do for j:=1 to length(y) do if x[i] = y[j] then c[i,j]:=c[i-1,j-1]+1 else if c[i-1,j] > c[i,j-1] then c[i,j]:=c[i-1,j] else c[i,j]:=c[i,j-1]; i:=length(x); j:=length(y); z:=''; writeln(i:4,j:4); writeln(c[i,j]); // :shu chu LCS while (i>0) and (j>0) do if x[i]= y[j] then begin z:=x[i]+z;i:=i-1;j:=j-1 end else if c[i-1,j]> c[i,j-1] then i:=i-1 else j:=j-1; if z<>'' then writeln(z); readln; end.