穷举法:
-
已知
X[1…m]
的一个子串X[i…j]
检测是否Y[1…n]
的子串? -
按照X,Y的下标递归扫描,看是否相同,扫描为
O(n)
- X多少个子串?
- 2 m,我们可以化为二进制考虑,然后每一个用0和1分别表示是否在串中
- 这个算法整个运行时间?
- 不难看出O( 2 mn),显然不好因为指数级的
简化
上面我们是从检测每个子串是否位于另一个序列中,这个会运行时间随着原来串的长度不断增加,必须从一个方面想,比如从序列长度入手
最优子结构,一个问题的最优解包含了子问题的最优解
LCS(X,Y)
存储在Z[1…k]
,那么Z[1…k]
的任何一个前缀 是 X[1…m]
的某个前缀和Y[1…n]
的某个前缀的LCS
证明不说:与另一篇博文MST的最优子结构证明方法一致
得到下面公式
- 先规定一下符号
-
求
X[1…m],Y[1…n]
的最长公共子序列记为LCS(X,Y)
存储在Z[1…k]
,然后|LCS(X,Y)|
表示最长公共子序列长度也就是K
|LCS(i,j)|
的最长公共子序列长度为L(i,j)
,也就是|LCS(X,Y)|
的最长公共子序列长度为L(X,Y)
公式证明
自顶向下递归
int LCS(X,Y,i,j)
{
if(i==0||j==0) return c[i,j]
if(X[i]==Y[j]) {c[i,j]=LCS(X,Y,i-1,j-1)+1}
else{
c[i,j]=max(LCS(X,Y,i-1,j),LCS(X,Y,i,j-1))
}
return c[i,j]
}
最坏情况:全是第二种情况
树的高度最高:m+n,说明运算是指数阶的
重叠子问题
LCS只包含了mn个独立的子问题,所以需要找一个方法只需要计算mn个问题
改进:自顶向下备忘法
int LCS(X,Y,i,j)
{
if(i==0||j==0) return c[i,j]
if (c[i,j]==nil)
{
if(X[i]==Y[j]) {c[i,j]=LCS(X,Y,i-1,j-1)+1 //可以输出}
else{
c[i,j]=max(LCS(X,Y,i-1,j),LCS(X,Y,i,j-1))
}
}
return c[i,j]
}
运行时间:Θ(mn)
空间:Θ(mn)
运行时间分析:平摊分析
再改进:真动态规划,自顶向下备忘法计算表格
int LCS(X,Y,m,n)
{
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;
}
else {
c[i,j] = max(c[i,j - 1], c[i - 1,[j]);
}
}
}
}
运行时间:Θ(mn)
空间:Θ(mn) 可以改进Θ({m,n})
使用回溯法获取
代码
#include <iostream>
using namespace std;
int max(int x, int y)
{
if (x >= y)
return x;
else
return y;
}
int c[8][7]; //需要大一圈
int LCS(char *X, char *Y, int i, int j) //自顶向下
{
if (i == 0 || j == 0) c[i][j] = 0;
if (c[i][j] == -1)
{
if (X[i-1] == Y[j-1]) {
c[i][j] = LCS(X, Y, i - 1, j - 1) + 1;
}
else {
c[i][j] = max(LCS(X, Y, i - 1, j), LCS(X, Y, i, j - 1));
}
}
return c[i][j];
}
void LCS1(char *X, char *Y, int m, int n) //自底向上计算表格
{
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;
}
else {
c[i][j] = max(c[i][j - 1], c[i - 1][j]);
}
}
}
}
int main()
{
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 7; y++)
{
c[x][y] = -1;
}
}
char A[7] = { 'A','B','C','B','D','A','B' }; //7
char B[6] = { 'B','D','C','A','B','A' }; //6
LCS(A, B, 7, 6);
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 7; y++)
{
cout << c[x][y]<<
" ";
}
cout <<"\n";
}
}
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 7; y++)
{
c[x][y] =0;
}
}
char A[7] = { 'A','B','C','B','D','A','B' };
char B[6] = { 'B','D','C','A','B','A' };
LCS1(A, B, 7, 6);
cout << "\n";
for (int x = 0; x <= 7; x++)
{
for (int y = 0; y <= 6; y++)
{
cout << c[x][y] << " ";
}
cout << "\n";
}
}
int a;
cin >>a;
return 0;
}