简介
最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。 [1]
最长公共子序列问题是一个经典的计算机科学问题,也是数据比较程序,比如Diff工具,和生物信息学应用的基础。它也被广泛地应用在版本控制,比如Git用来调和文件之间的改变。
算法
动态规划的一个计算两个序列的最长公共子序列的方法如下:
以两个序列 X、Y 为例子:
设有二维数组f[i,j] 表示 X 的 i 位和 Y 的 j 位之前的最长公共子序列的长度,则有:
f[1][1] = same(1,1);
f[i,j] = max{f[i-1][j -1] + same(i,j),f[i-1,j],f[i,j-1]};
其中,same(a,b)当 X 的第 a 位与 Y 的第 b 位相同时为“1”,否则为“0”。
此时,二维数组中最大的数便是 X 和 Y 的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。
该算法的空间、时间复杂度均为O(n^2),经过优化后,空间复杂度可为O(n)
具体实现代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1024;
int c[N][N], b[N][N];
char s1[N], s2[N];
int len1, len2;
void LCS()
{
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (s1[i - 1] == s2[j - 1]) {
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 1;//左上角
}
else {
if (c[i][j - 1] >= c[i - 1][j]) {
c[i][j] = c[i][j - 1];//上
b[i][j] = 2;
}
else {
c[i][j] = c[i - 1][j];//左
b[i][j] = 3;
}
}
}
}
}
void LCS_PRINT(int i, int j)
{
if (i == 0 || j == 0) {
return;
}
if (b[i][j] == 1) {
LCS_PRINT(i - 1, j - 1);
cout << s1[i - 1];
}
else if (b[i][j] == 2) {
LCS_PRINT(i, j - 1);
}
else {
LCS_PRINT(i - 1, j);
}
}
int main()
{
cout << "请输入X字符串" << endl;
cin >> s1;
cout << "请输入Y字符串" << endl;
cin >> s2;
len1 = strlen(s1);
len2 = strlen(s2);
for (int i = 0; i <= len1; i++) {
c[i][0] = 0;
}
for (int j = 0; j <= len2; j++) {
c[0][j] = 0;
}
LCS();
cout << "s1与s2的最长公共子序列的长度是:" << c[len1][len2] << endl;
cout << "s1与s2的最长公共子序列是:";
LCS_PRINT(len1, len2);
return 0;
}