一、前言
求解两个字符串的最长公共子串(Longest Common Substring, LCS)与求解两个字符串的最长公共子序列(Longest Common Subsequence, LCS)是不一样的,求解最长公共子序列问题请参阅我的另一篇博客
http://blog.csdn.net/heart_love/article/details/50804301
假定给出两个字符串X=“abcdef"和Y=“abacdef"那么"a"、"ab"、"cdef"等都是其公共子串,其中"cdef"是X和Y的最长公共子串。
二、求解算法
对于两个字符串X={x1,x2,....xm}和Y={y1,y2,.....yn},我们利用一个二维数组c[i][j]来记录Xi与Yj是否相等,如果Xi == Yj,那么c[i][j] = 1,否则c[i][j] = 0。如下图所示:
然后我们遍历所有的斜下角,找出最多的连续为1的值。这种遍历太浪费时间,我们把算法改进一下:如果Xi == Yj,那么c[i][j] = c[i - 1][j - 1] + 1,否则c[i][j] = 0。如下图所示:
然后我们找出二维数组中的最大值,即可求出其最长公共子串。此算法还有一个缺点就是所使用的二维数组占用了过的内存,我们继续对算法进行改进,使用一维数组来保存值:具体算法如下面的代码所示
#include <iostream>
using namespace std;
char *lcs(const char X[],const char Y[],char str[]);
int main()
{
char str[1024];
lcs("aecdfab", "abecdfa", str);
cout << str << endl;
}
char *lcs(const char X[], const char Y[], char str[])
{
int Xlen = strlen(X);
int Ylen = strlen(Y);
int *pre = (int *)malloc(sizeof(int)* Ylen);//用来记录前一行的数据
int *cur = (int *)malloc(sizeof(int)* Ylen);//用来记录当前行的数据
int max[2] = { 0 }; //max[0]用来记录最长公共子串的长度,max[1]用来记录此时X串的下表
int i, j;
/*初始化pre数组*/
for (j = 0; j < Ylen; j++)
{
if (X[0] == Y[j])
{
pre[j] = 1;
max[0] = pre[j] > max[0] ? pre[j]:max[0];
}
else
pre[j] = 0;
}
for (i = 1; i < Xlen; i++)
{
for (j = 0; j < Ylen;j++)
{
if (j == 0)
{
if (X[i] == Y[0])
{
cur[0] = 1;
max[0] = cur[0] > max[0] ? cur[0] : max[0];
max[1] = cur[0] > max[0] ? i : max[1];
}else
cur[0] = 0;
}else
{
if (X[i] == Y[j])
{
cur[j] = pre[j - 1] + 1;
max[1] = cur[j] > max[0] ? i : max[1];
max[0] = cur[j] > max[0] ? cur[j] : max[0];
}
else
cur[j] = 0;
pre[j - 1] = cur[j - 1];
}
}
pre[j] = cur[j];
}
strncpy(str, X + max[1] - max[0] + 1, max[0]);
str[max[0]] = '\0';
free(pre);
free(cur);
return str;
}
运行结果为: