最长公共子序列问题(LCS)
公共子序列的意思是在两个序列中,按顺序找出共同出现的元素,这些元素按顺序排列就是原序列的子序列:例如A=zxyxyz,B=xyyzx;则A和B的一个公共子序列为:xyy,而最长公共子序列是:xyyz。因此,A和B的LCS长度为4.
POJ和HDU上面有LCS的题目,下边给出入门级别的题目:
(1)先说一下暴力方案( • ̀ω ⁃᷄)✧
- 设序列A长度为n,序列B长度为m。
- 列举出A所有的 2n 2 n 个子序列,对于每一个子序列在 Θ(m) Θ ( m ) 时间内来确定它是否也是B的子序列。
很明显,此算法的时间复杂度 Θ(m2n) Θ ( m 2 n )
这个方案想法简单,但很可能TLE(time limited exceed),所以就有了下面的算法———
(2)动态规划 Σ>―(〃°ω°〃)♡→
为了方便理解问题,我们约定序列的起始地址为1,而不是0。
首先我们寻找求LCS长度的状态转移方程(也就是递推式)。
令
A=a1a2...an
A
=
a
1
a
2
.
.
.
a
n
,
B=b1b2...bm
B
=
b
1
b
2
.
.
.
b
m
.
令
L[i][j]
L
[
i
]
[
j
]
表示
a1a2...ai
a
1
a
2
.
.
.
a
i
和
b1b2...bj
b
1
b
2
.
.
.
b
j
的最长公共子序列的长度。
注意
i
i
和可能是0,此时,
a1a2...ai
a
1
a
2
.
.
.
a
i
和
b1b2...bj
b
1
b
2
.
.
.
b
j
中的一个或同时为空串。即如果
i=0
i
=
0
或
j=0
j
=
0
,那么
L[i][j]=0
L
[
i
]
[
j
]
=
0
.
容易得出以下LCS递推式:
L[i][j]=⎧⎩⎨0,L[i−1][j−1]+1,max{L[i][j−1],L[i−1][j]},if i=0或j=0 if i>0,j>0 and ai=bj if i>0,j>0 and ai≠bj
L
[
i
]
[
j
]
=
{
0
,
if
i
=
0
或
j
=
0
L
[
i
−
1
]
[
j
−
1
]
+
1
,
if
i
>
0
,
j
>
0
and
a
i
=
b
j
m
a
x
{
L
[
i
]
[
j
−
1
]
,
L
[
i
−
1
]
[
j
]
}
,
if
i
>
0
,
j
>
0
and
a
i
≠
b
j
递推式解释:
- 我们假设无论是 L[i−1][j−1] L [ i − 1 ] [ j − 1 ] 还是 L[i][j−1],L[i−1][j] L [ i ] [ j − 1 ] , L [ i − 1 ] [ j ] 都已经解出。现在来求 L[i][j] L [ i ] [ j ] 。
- 当 i>0,j>0 i > 0 , j > 0 and ai=bj a i = b j 时,意味着A和B对应位置相等,因此该位置也是LCS的一部分,LCS长度+1。
- 当
i>0,j>0
i
>
0
,
j
>
0
and
ai≠bj
a
i
≠
b
j
时,意味着当前遍历到的序列对应位置不相等。而
L[i][j]
L
[
i
]
[
j
]
的值必定是
a1a2...ai-1与b1b2..bj的LCS长度(即 L[i−1][j] L [ i − 1 ] [ j ] ) 和a1a2...ai与b1b2..bj-1的LCS长度(即 L[i][j−1] L [ i ] [ j − 1 ] )中的较大者。
现在,我们构建一个(n+1)x(m+1)表来计算L[i][j],只需要用上面的公式逐行填表。见下面C++代码
#include<iostream>
#include<string>
#define Max(a,b) ((a)>(b))?(a):(b)
using namespace std;
string A,B;
int L[100][100];
int main(){
int n,m;
int i,j;
cin>>A>>B;//读取字符串
n=A.length();//计算长度
m=B.length();
for(i=0;i<=n;i++){//初始化j=0的情况
L[i][0]=0;
}
for(j=0;j<=m;j++){//初始化i=0的情况
L[0][j]=0;
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(A[i-1]==B[j-1])
L[i][j]=L[i-1][j-1]+1;
else
L[i][j]=Max(L[i][j-1],L[i-1][j]);
}
}
cout<<L[n][m]<<endl;
return 0;
}
程序运行结果如图:

把上面的代码修改一下就可以刷POJ和HDU的那两道题啦。
本文详细介绍了最长公共子序列(LCS)问题,通过暴力求解和动态规划两种方法进行讲解。动态规划方案中,给出了LCS的递推式,并解释了状态转移的过程。最后,提供了C++代码示例,适用于解决相关问题。
&spm=1001.2101.3001.5002&articleId=81274321&d=1&t=3&u=e15a5c161bbe4407b54b20c820b87f97)
1598

被折叠的 条评论
为什么被折叠?



