1. 问题

图片.png

2. 解析

求两个字符串的最长公共子序列(lcs算法).
字符串:GCCCT GCGCA

用一个二维数组表示
图片.png
在填充单元格时,需要考虑以下条件:
它左侧的单元格
它上面的单元格
它左上侧的单元格
下面三个值分别对应着我在前面列出的三个递归子问题返回的值。
V1 = 左侧单元格的值
V2 = 上面单元格的值
V3 = 左上侧单元格的值
在空单元格中填充下面 3 个数字中的最大值:
V1
V2
如果 C1 等于 C2 则为 V3 + 1,如果 C1 不等于 C2,则为 V3 ,其中 C1 是当前单元格上面的字符,C2 是当前单元格左侧的字符
请注意,我在图中还添加了箭头,指向当前单元格值的来源。后面的 “回溯” 一节将用这些箭头建立实际的 LCS(与仅仅发现 LCS 长度相反)。
图片.png

3. 设计

[void LCS_LENGTH(string X, string Y){
int m = X.length();
int n = Y.length();
for (int i = 1; i <= m; i++)
c[i][0] = 0;
for (int j = 0; j <= n; j++)
c[0][j] = 0;
for (int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
if (X[i - 1] == Y[j - 1]){
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = ‘a’;
}
else if (c[i - 1][j] >= c[i][j - 1]){
c[i][j] = c[i - 1][j];
b[i][j] = ‘b’;
}
else{
c[i][j] = c[i][j - 1];
b[i][j] = ‘c’;
}
}
}
}

void PRINT_LCS(string X,int m, int n)
{
if (m == 0 || n == 0)
return;
if (b[m][n] == ‘a’){
PRINT_LCS(X,m - 1, n - 1);
cout << X[m-1];
}
else if (b[m][n] == ‘b’){
PRINT_LCS(X, m - 1, n);
}
else
PRINT_LCS(X, m, n - 1);

4. 分析

时间复杂度O(mn)

5. 源码

https://github.com/joserfdave/arithmetic/tree/main