一个字符串S,去掉零个或者多个元素所剩下的子串称为S的子序列。最长公共子序列就是寻找两个给定序列的子序列,该子序列在两个序列中以相同的顺序出现,但是不必要是连续的。
例如序列X=ABCBDAB,Y=BDCABA。序列BCA是X和Y的一个公共子序列,但是不是X和Y的最长公共子序列,子序列BCBA是X和Y的一个LCS,序列BDAB也是。
暴力解法
寻找LCS的一种方法是枚举X所有的子序列,然后注意检查是否是Y的子序列,并随时记录发现的最长子序列。假设X有m个元素,则X有2^m个子序列,指数级的时间,对长序列不实际。
动态规划
使用动态规划求解这个问题,先寻找最优子结构。
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
int LCS(const string& a, const string& b) //递归
{
if (a.empty() || b.empty())
return 0;
if (a[0] == b[0])
return LCS(a.substr(1), b.substr(1)) + 1;
else
return max(LCS(a.substr(1), b), LCS(a, b.substr(1)));
}
void LCS(const string& a, const string& b)//DP解法
{
int aSize = a.size();
int bSize = b.size();
vector<vector<int>> v(aSize + 1, vector<int>(bSize + 1, 0));
for (int i = 1; i < aSize + 1; i++)
{
for (int j = 1; j < bSize + 1; j++)
{
if (a[i - 1] == b[j - 1])
{
v[i][j] = v[i - 1][j - 1] + 1;
}
else
{
v[i][j] = max(v[i][j - 1], v[i - 1][j]);
}
}
}
cout << v[aSize][bSize] << endl;
//根据表回溯出最长公共子序列,注意由于最长公共子序列可能不止一个,在这里只打印一个
string output = "";
int i = aSize - 1;
int j = bSize - 1;
while (i > 0 || j > 0)
{
if (a[i - 1] == b[j - 1])
{
output += a[i - 1];
i--;
j--;
}
else
{
if (v[i - 1][j] < v[i][j - 1])
{
j--;
}
else
{
i--;
}
}
}
reverse(output.begin(), output.end());
cout << output << endl;
}
int main()
{
LCS("hello", "hxlolll");
return 0;
}