最大公共子串 LCS

这个LCS跟前面说的最长公共子序列的LCS不一样,不过也算是LCS的一个变体,在LCS中,子序列是不必要求连续的,而子串则是“连续”的。即:

题:给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa]。二者的最长公共子串为[aba],长度为3。

基本算法

其实对于最长公共子串,还是比较简单易想的,因为子串是连续的,这就方便了很多。最直接的方法就是用X每个子串与Y的每个子串做对比,求出最长的公共子串。代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 最长公共子串 Longest Common Substring */
  
int maxlen;    /* 记录最大公共子串长度 */
int maxindex;  /* 记录最大公共子串在串1的起始位置 */
void outputLCS(char * X);  /* 输出LCS */
  
/* 最长公共子串 基本算法 */
int comlen(char * p, char * q)
{
    int len = 0;
    while(*p && *q && *p++ == *q++)
    {
        ++len;
    }
    return len;
}
  
void LCS_base(char * X, int xlen, char * Y, int ylen)
{
    for(int i = 0; i < xlen; ++i)
    {
        for(int j = 0; j < ylen; ++j)
        {
            int len = comlen(&X[i],&Y[j]);
            if(len > maxlen)
            {
                maxlen = len;
                maxindex = i;
            }
        }
    }
    outputLCS(X);
}

==================================复杂度O(n^3)

动态规划

使用dp[i][j]表示 以x[i]和y[j]结尾的最长公共子串的长度,因为要求子串连续,所以对于X[i]与Y[j]来讲,它们要么与之前的公共子串构成新的公共子串;要么就是不构成公共子串。故状态转移方程 X[i] == Y[j],dp[i][j] = dp[i-1][j-1] + 1 X[i] != Y[j],dp[i][j] = 0 对于初始化,i==0或者j==0,如果X[i] == Y[j],dp[i][j] = 1;否则dp[i][j] = 0。

C代码 复制代码 收藏代码
  1. /* 最长公共子串 DP */  
  2. int dp[30][30];   
  3.     
  4. void LCS_dp(char * X, int xlen, char * Y, int ylen)   
  5. {   
  6.     maxlen = maxindex = 0;   
  7.     for(int i = 0; i < xlen; ++i)   
  8.     {   
  9.         for(int j = 0; j < ylen; ++j)   
  10.         {   
  11.             if(X[i] == Y[j])   
  12.             {   
  13.                 if(i && j)   
  14.                 {   
  15.                     dp[i][j] = dp[i-1][j-1] + 1;   
  16.                 }   
  17.                 if(i == 0 || j == 0)   
  18.                 {   
  19.                     dp[i][j] = 1;   
  20.                 }   
  21.                 if(dp[i][j] > maxlen)   
  22.                 {   
  23.                     maxlen = dp[i][j];   
  24.                     maxindex = i + 1 - maxlen;   
  25.                 }   
  26.             }   
  27.         }   
  28.     }   
  29.     outputLCS(X);   
  30. }  

复杂度分析:O(n^2);和最大公共子序列复杂度一样。

各方案复杂度对比

设字符串X的长度为m,Y的长度为n,最长公共子串长度为l。

对于基本算法,X的子串(m个)和Y的子串(n个)一一对比,最坏情况下,复杂度为O(m*n*l),空间复杂度为O(1)。

对于DP算法,由于自底向上构建最优子问题的解,时间复杂度为O(m*n);空间复杂度为O(m*n),当然这里是可以使用滚动数组来优化空间的,滚动数组在动态规划基础回顾中多次提到。

posted @ 2013-08-29 18:32  sandyhit  阅读(147)  评论(0)    收藏  举报