最长公共子序列的概念:
若 Z < X,Z < Y,且不存在比Z更长的X 和Y 的公共子序列,则称Z是X 和Y 的最长公共子序列,记为Z∈LCS(X , Y)。
问题:找出X 和Y 的一个最长公共子序列?
引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们
根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。
LCSTestMain.c
#include
<
stdio.h
>
#include < string .h >
#define MAXLEN 100
void LCSLength( char * x, char * y, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
... {
int i, j;
for(i = 0; i <= m; i++)
c[i][0] = 0;
for(j = 1; j <= n; j++)
c[0][j] = 0;
for(i = 1; i<= m; i++)
...{
for(j = 1; j <= n; j++)
...{
if(x[i-1] == y[j-1])
...{
c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 0;
}
else if(c[i-1][j] >= c[i][j-1])
...{
c[i][j] = c[i-1][j];
b[i][j] = 1;
}
else
...{
c[i][j] = c[i][j-1];
b[i][j] = -1;
}
}
}
}
void PrintLCS( int b[][MAXLEN], char * x, int i, int j)
... {
if(i == 0 || j == 0)
return;
if(b[i][j] == 0)
...{
PrintLCS(b, x, i-1, j-1);
printf("%c ", x[i-1]);
}
else if(b[i][j] == 1)
PrintLCS(b, x, i-1, j);
else
PrintLCS(b, x, i, j-1);
}
int main( int argc, char ** argv)
... {
char x[MAXLEN] = ...{"ABCBDAB"};
char y[MAXLEN] = ...{"BDCABA"};
int b[MAXLEN][MAXLEN];
int c[MAXLEN][MAXLEN];
int m, n;
m = strlen(x);
n = strlen(y);
LCSLength(x, y, m, n, c, b);
PrintLCS(b, x, m, n);
return 0;
}
#include < string .h >
#define MAXLEN 100
void LCSLength( char * x, char * y, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
... {
int i, j;
for(i = 0; i <= m; i++)
c[i][0] = 0;
for(j = 1; j <= n; j++)
c[0][j] = 0;
for(i = 1; i<= m; i++)
...{
for(j = 1; j <= n; j++)
...{
if(x[i-1] == y[j-1])
...{
c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 0;
}
else if(c[i-1][j] >= c[i][j-1])
...{
c[i][j] = c[i-1][j];
b[i][j] = 1;
}
else
...{
c[i][j] = c[i][j-1];
b[i][j] = -1;
}
}
}
}
void PrintLCS( int b[][MAXLEN], char * x, int i, int j)
... {
if(i == 0 || j == 0)
return;
if(b[i][j] == 0)
...{
PrintLCS(b, x, i-1, j-1);
printf("%c ", x[i-1]);
}
else if(b[i][j] == 1)
PrintLCS(b, x, i-1, j);
else
PrintLCS(b, x, i, j-1);
}
int main( int argc, char ** argv)
... {
char x[MAXLEN] = ...{"ABCBDAB"};
char y[MAXLEN] = ...{"BDCABA"};
int b[MAXLEN][MAXLEN];
int c[MAXLEN][MAXLEN];
int m, n;
m = strlen(x);
n = strlen(y);
LCSLength(x, y, m, n, c, b);
PrintLCS(b, x, m, n);
return 0;
}
算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m + n)。