[算法]最长公共子序列–LCS(Longest Common Subsequence)

  • Post author:
  • Post category:其他


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_1

回溯输出最长公共子序列过程:

flow

如何输出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("\n");
    }
        printf("\n");
        printf("\n");
        
        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("\n");
    printf("LCS is %d\n",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.

转载于:https://www.cnblogs.com/rainboy/p/3696126.html