(说明:由于优快云的博客中不能添加下标等特殊符号,所以部分内容使用截图的形式)
static void print_lcs(int **b, char *x, int i, int j)
{
int key;
if (i == 0 || j == 0) {
return;
}
key = b[i-1][j-1];
switch (key) {
case 0:
print_lcs(b, x, i - 1, j - 1);
printf("%c ", x[i-1]);
break;
case 1:
print_lcs(b, x, i - 1, j);
break;
case 2:
print_lcs(b, x, i, j - 1);
break;
default:
break;
}
}
static void lcs_length(char *x, int m, char *y, int n)
{
int b[m][n];
int *p[m];
int c[m+1][n+1];
int i,j;
for (i = 1; i <= m; ++i) {
c[i][0] = 0;
}
for (j = 0; 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-1][j-1] = 0;
} else if (c[i-1][j] >= c[i][j-1]) {
c[i][j] = c[i-1][j];
b[i-1][j-1] = 1;
} else {
c[i][j] = c[i][j-1];
b[i-1][j-1] = 2;
}
}
}
for (i = 0; i < m; ++i) {
p[i] = b[i];
}
print_lcs(p, x, m, n);
printf("\n");
}
lcs_length()函数中前两个循环分别初始化为序列Y长度为0、序列X长度为0的情况。只要有一个序列的长度为0,则最大公共子序列的长度为0.接下来的两个嵌套循环用来计算X序列和Y序列长度不同时,最大公共子序列的长度,并存储计算最大子序列时选择的子问题最优解。
print_lcs()我们这里使用的是递归来实现,还可以使用循环来代替递归,提高效率。不过在使用循环时,要分配额外的空间来存储最大公共子序列,代码实现如下:
static void print_lcs(int **b, char *x, int i, int j, int length)
{
char lcs[length];
int k = length - 1;
do {
if (i == 0 || j == 0) {
break;
}
switch (b[i-1][j-1]) {
case 0:
lcs[k--] = x[i-1];
i = i - 1;
j = j - 1;
break;
case 1:
i = i - 1;
break;
case 2:
j = j - 1;
break;
default:
break;
}
} while(1);
for (i = 0; i < length; ++i) {
printf("%c ", lcs[i]);
}
}
参数中的length就是X序列和Y序列最大公共子序列的长度,可以计算完c数组和b数组之后,通过c[m][n]获取。