动态规划学习三 | 最长公共子序列
动态规划学习三 | 最长公共子序列
动态规划 之 最长公共子序列 过程图
- 求最长公共子序列的长度
- 倒推构造最长公共子序列
算法推导:动态规划算法解最长公共子序列LCS问题
记:
Xi=﹤x1,⋯,xi﹥即X序列的前i个字符 (1≤i≤m)(前缀)
Yj=﹤y1,⋯,yj﹥即Y序列的前j个字符 (1≤j≤n)(前缀)
假设: Z=﹤z1,⋯,zk﹥∈LCS(X , Y)
-
若xm=yn(最后一个字符相同)
用反证法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有zk = xm = yn 且显然有Zk-1∈LCS(Xm-1 , Yn-1)即Z的前缀Zk-1是Xm-1与Yn-1的最长公共子序列。
此时,问题化归成求Xm-1与Yn-1的LCS(LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1)的长度加1)
-
若xm≠yn ( 最后一个字符不相同 )
要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。由于zk≠xm与zk≠yn其中至少有一个必成立,若zk≠xm则有Z∈LCS(Xm-1 , Y),类似的,若zk≠yn 则有Z∈LCS(X , Yn-1)。此时,问题化归成求Xm-1与Y的LCS及X与Yn-1的LCS。LCS(X , Y)的长度为:max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}
由于上述当xm≠yn的情况中,求LCS(Xm-1 , Y)的长度与LCS(X , Yn-1)的长度,这两个问题不是相互独立的:两者都需要求LCS(Xm-1,Yn-1)的长度。另外两个序列的LCS中包含了两个序列的前缀的LCS,故问题具有最优子结构性质考虑用动态规划法。
也就是说,解决这个LCS问题,你要求三个方面的东西:1、LCS(Xm-1,Yn-1)+1;2、LCS(Xm-1,Y),LCS(X,Yn-1);3、max{LCS(Xm-1,Y),LCS(X,Yn-1)}。
Procedure LCS_LENGTH(X,Y);
begin
m:=length[X];
n:=length[Y];
for i:=1 to m do c[i,0]:=0;
for j:=1 to n do c[0,j]:=0;
for i:=1 to m do
for j:=1 to n do
if x[i]=y[j] then
begin
c[i,j]:=c[i-1,j-1]+1;
b[i,j]:="↖";
end
else if c[i-1,j]≥c[i,j-1] then
begin
c[i,j]:=c[i-1,j];
b[i,j]:="↑";
end
else
begin
c[i,j]:=c[i,j-1];
b[i,j]:="←"
end;
return(c,b);
代码实现
1. 计算LCS长度
2 . 构造一个LCS
#include "MyInclude.h"
int lcs(string str1, string str2, vector <vector<int> >&dir) {
int len1 = str1.size();
int len2 = str2.size();
// c[i][j] 表示 str1[0..i-1]与st2[0..j-1]的最长公共子序列长度
vector<vector<int>> c(len1 + 1, vector<int>(len2 + 1, 0));
for (int i = 1; i < len1 + 1; ++i) {
for (int j = 1; j < len2 + 1; ++j) {
if (str1[i - 1] == str2[j - 1]) {
// 最后一个字符相等
c[i][j] = c[i - 1][j - 1] + 1;
dir[i][j] = 0; // 左上
}
else {
// 最后一个字符不相等
if (c[i - 1][j]>=c[i][j - 1]) {
c[i][j] = c[i - 1][j];
dir[i][j] = 1; // 上
} else {
c[i][j] = c[i][j - 1];
dir[i][j] = 2; // 左
}
}
}
}
// 返回最大长度
return c[len1][len2];
}
void print_lcs(vector < vector<int> >&dir, string str, int i, int j) {
if (i == 0 || j == 0) {
return;
}
if (dir[i][j] == 0) {
print_lcs(dir, str, i - 1, j - 1);
std:cout << str[i-1];
}
else if (dir[i][j] == 1) {
print_lcs(dir, str, i - 1, j );
}
else {
print_lcs(dir, str, i , j - 1);
}
}
int main() {
string s1 = "abcd";
string s2 = "bd";
int len1 = s1.size();
int len2 = s2.size();
vector<vector<int>> dir(len1 + 1, vector<int>(len2 + 1, 0));
int res = lcs(s1, s2, dir);
print_lcs(dir, s1, len1 , len2 );
system("pause");
return 0;
}