划分子问题
- 如果最后一位相同,则X(i - 1) 与 Y (j - 1)的最长公共子序列 + Xi就是X(i)与Y(j)的最长公共子序列
- 如果Xi与yi不相同,则X(i-1)与Y(j)和X(i)与Y(j-1)的最长公共子序列就是X(i)与Y(j)的最长公共子序列
- 因此,子序列长度存在下面的关系
- L(i, j) = L(i-1, j-1) + 1 xi = yi, i>=1,j>=1; max{L(i, j-1), L(i-1,j)} xi != yi, i>=1,j>=1
- 根据3中不同情况分别设置不同的状态
- s(i,j) xi = yi => 1, xi != yi && L(i, j-1) >= L(i-1, j) = > 2, xi != yi && L(i,j-1) < L(i-1, j) => 3
- 然后根据上述条件填表,最终得到表如下:result = L表,S=S表
代码实现
#include <iostream>
#include <string>
using namespace std;
// 初始化
void init(int (*arr)[10], int (*S)[10]) {
for (int i = 0; i<7; i++) {
for (int j = 0; j<10; j++) {
arr[i][j] = 0;
S[i][j] = 0;
}
}
}
//
void getCurrentVal(int i, int j, string &x, string &y, int (*result)[10], int (*S)[10]) {
if (x[i-1] == y[j-1]) {
result[i][j] = result[i-1][j-1] + 1;
S[i][j] = 1;
} else if (x[i-1] != y[j-1]) {
// L(i,j) = max(L(i, j-1),L(i-1,j))
result[i][j] = result[i][j-1] >= result[i-1][j] ? result[i][j-1] : result[i-1][j];
S[i][j] = result[i][j-1] >= result[i-1][j] ? 2 : 3;
}
}
int getLength(string& X, string& Y) {
int result[7][10];
int S[7][10];
// 初始化矩阵
init(result, S);
int i = 0, j = 0;
// 循环处理
for(i = 1; i <= X.length(); i++) {
for (j = 1; j <= Y.length(); j++) getCurrentVal(i, j, X, Y, result, S);
}
for(i = 0; i <= X.length(); i++) {
for (j = 0; j <= Y.length(); j++) cout<<result[i][j];
cout<<endl;
}
cout<<endl;
for(i = 0; i <= X.length(); i++) {
for (j = 0; j <= Y.length(); j++) cout<<S[i][j];
cout<<endl;
}
cout<<"最长公共子序列-》";
int k = X.length(), m = Y.length();
while(k > 0 && m > 0) {
if (S[k][m] == 1) {
cout<<X[k-1];
k--;m--;
} else if (S[k][m] == 2) m--;
else k--;
}
return 0;
};
int main() {
string X = "abcbdb";
string Y = "acbbabdbb";
getLength(X, Y);
return 0;
}
总结
最后取结果的时候,从后往回取,状态是1的则表示符合最长公共子序列,如果是2左移(左移是因为我们在前面设置条件的时候设置了关系),否则上移。
ps:本文算法不是最优写法,只是为了容易理解,把代码写的更加易读和输出了计算过程的信息。