最长公共子串
题:给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa]。二者的最长公共子串为[aba],长度为3。
1 基本算法
其实对于最长公共子串,还是比较简单易想的,因为子串是连续的,这就方便了很多。
最直接的方法就是用X每个子串与Y的每个子串做对比,求出最长的公共子串。
2 DP方案
既然最长公共子串是最长公共子序列的变体,那么最长公共子串是不是也可以用动态规划来求解呢?
我们还是像之前一样“从后向前”考虑是否能分解这个问题,在最大子数组和中,
我们也说过,对于数组问题,可以考虑“如何将arr[0,...i]的问题转为求解arr[0,...i-1]的问题”,
类似最长公共子序列的分析,这里,我们使用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。
#include<stdio.h>
#include<string.h>
void outputLCS(char * X);
// 最长公共子串 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);
}
// 最长公共子串 DP ======================================
int dp[30][30];
void LCS_dp(char * X, int xlen, char * Y, int ylen)
{
maxlen = maxindex = 0;
for(int i = 0; i < xlen; ++i)
{
for(int j = 0; j < ylen; ++j)
{
if(X[i] == Y[j])
{
if(i && j)//i>0 && j>0
{
dp[i][j] = dp[i-1][j-1] + 1;
}
if(i == 0 || j == 0)
{
dp[i][j] = 1;
}
if(dp[i][j] > maxlen)
{
maxlen = dp[i][j];
maxindex = i + 1 - maxlen;
}
}
}
}
outputLCS(X);
}
//============ common code =============================
void outputLCS(char * X)
{
if(maxlen == 0)
{
printf("NULL LCS\n");
return;
}
printf("The len of LCS is %d\n",maxlen);
int i = maxindex;
while(maxlen--)
{
printf("%c",X[i++]);
}
printf("\n");
}
void main()
{
char X[] = "aaaba";
char Y[] = "abaa";
/* 基本算法 */
LCS_base(X,strlen(X),Y,strlen(Y));
/* DP算法 */
LCS_base(X,strlen(X),Y,strlen(Y));
}

浙公网安备 33010602011771号