问题描述
求两字符序列的最长公共字符子序列。
补充说明:
- 不强制要求子串的字符连续出现在原始的2个字符序列中。
- 测试字符序列,比如,
Name | Value |
---|---|
第1个字符序列 S[x] | {‘A’, ‘B’, ‘C’, ‘B’, ‘D’, ‘A’, ‘B’} |
第2个字符序列 W[y] | {‘B’, ‘D’, ‘C’, ‘A’, ‘B’, ‘A’} |
解决思路
确立状态方程
参考图1.表格所示,记 LCS(x, y) 为表格中的元素,该元素表示截止到第1序列中的字符‘x’和第2序列中的字符‘y’时已有多少个相同的字符个数,即公共子序列的长度。
图1.
⎧⎩⎨LCS(x,y)=LCS(x−1,y−1)+1,LCS(x,y)=max(LCS(x−1,y),LCS(x,y−1)),LCS(0,0)=0,if S(x) = W(y)if S(x) != W(y)if x = 0 or y = 0
图1.中箭头的方向表示当前的“公共子序列长度”继承自哪个前一个位置,这里,如果有
[LCS(x−1,y)=LCS(x,y−1),且 S(x) != W(y)]
的情况,则如
图1.所示,当前LCS(x, y)元素值优先继承自纵轴上方的那个(箭头↑)。由此,亦可以看出,最长公共子序列并非唯一的。
代码
///////////////////////////////////////////////////////////////
//
// @2017-10-13 DP : LCS 最长公共子序列
// 时间复杂度 O(n*m)
// 空间复杂度 O(n*m)
//
///////////////////////////////////////////////////////////////
// 头文件
#include <iostream>
#include <vector>
using namespace std;
//@2017-10-13 TY 需考虑使用变长度数组 , 考虑使用 vector 实现变长二维数组
#define ArraySize 16
int dp[ArraySize][ArraySize]={0};
///////////////////////////////////////////////////////////////
// DP LCS API
void DpLCS(vector<char>::iterator pVecX, vector<char>::iterator pVecY, int x, int y);
///////////////////////////////////////////////////////////////
//
int main(void)
{
char cBufX[] = {'A', 'B', 'C', 'B', 'D', 'A', 'B'};
char cBufY[] = {'B', 'D', 'C', 'A', 'B', 'A'};
vector<char> vecX, vecY;
// 赋初值
for (int i=0; i<(sizeof(cBufX)/sizeof(char)); i++)
{
vecX.push_back(cBufX[i]);
//cout << vecX[i] << " ";
}
for (int i=0; i<(sizeof(cBufY)/sizeof(char)); i++)
{
vecY.push_back(cBufY[i]);
//cout << vecY[i] << " ";
}
// DP : LCS
// 二维数组存储的是 状态方程 的值
for (int i=0; i<vecX.size(); i++)
{
for (int j=0; j<vecY.size(); j++)
{
if (vecX.at(i) == vecY.at(j))
{
dp[i+1][j+1] = dp[i][j]+1;
}
else
{
dp[i+1][j+1] = std::max(dp[i][j+1], dp[i+1][j]);
}
}
}
/*
// 打印 表格 content
for (int i=0; i<ArraySize; i++)
{
for (int j=0; j<ArraySize; j++)
{
cout << dp[i][j] << ' ';
}
cout << endl;
}
*/
// Graph
DpLCS(vecX.begin(), vecY.begin(), vecX.size(), vecY.size());
system("pause");
return 0;
}
///////////////////////////////////////////////////////////////
// @2017-10-13 DP LCS
// DP : LCS
// (1) 从数列结尾向前递归.
// (2) 结束的边界条件是 return ;
void DpLCS(vector<char>::iterator pVecX, vector<char>::iterator pVecY, int x, int y)
{
if (x == 0 || y == 0)
return ;
if (*(pVecX+x-1) == *(pVecY+y-1))
{
DpLCS(pVecX, pVecY, x-1, y-1);
cout << *(pVecX+x-1) << ' ';
}
else if (dp[x-1][y] == dp[x][y])
{
DpLCS(pVecX, pVecY, x-1, y);
}
else
{
DpLCS(pVecX, pVecY, x, y-1);
}
}