一、什么是最长公共子序列
什么是最长公共子序列呢?举个简单的例子吧,一个数列S,若分别是两个或多个已知序列的子序列,且是所有符合条件序列中最长的,则S称为已知序列的最长公共子序列。
举例如下,如:有两个随机数列,1 2 3 4 5 6 和 3 4 5 8 9,则它们的最长公共子序列便是:3 4 5。
一直不明白:最长公共子串和最长公共子序列的区别。
上网查了下,最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续。
给定两个序列X(x1,x2,x3…xm)和Y(y1, y2, y3…yn),求长度最大的公共子序列的长度。
例如:1,5,2,6,8,7 和 2,3,5,6,9,8,4 的LCS为5,6,8(另一个解是2,6,8)
dp[i][j]记录X[1~i]与Y[1~j] 的LCS 的长度
状态转移方程:dp[i][j] ={dp[i-1][j-1]+1(x[i]==y[j]),max(dp[i-1][j],dp[i][j-1])(x[i]!=y[j])}。
代码1:只能输出长度。
#include<iostream>
using namespace std;
int x[100], y[100], dp[100][100];
int main()
{
int xn, yn;
while (cin >> xn >> yn)
{
x[100] = y[100] = dp[100][100] = { 0 };
for (int i = 1; i <= xn; i++)
{
cin >> x[i];
}
for (int i = 1; i <= yn; i++)
{
cin >> y[i];
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
if (x[i] == y[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else
{
if (dp[i - 1][j] >= dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
}
else
{
dp[i][j] = dp[i][j - 1];
}
}
}
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
cout << dp[i][j] << ' ';
}
cout << endl;
}
cout << dp[xn][yn] << endl;
}
return 0;
}
输出结果
2,输出最长序列中的其中一个。(详细内容介绍请到另一篇转载文章)
代码实现:
#include<iostream>
using namespace std;
int x[100], y[100], dp[100][100], b[100][100];
void LCS(int b[100][100], int x[], int i, int j)
{
if (i == 0 && j == 0)
{
return;
}
if (b[i][j] == 1)
{
LCS(b, x, i - 1, j - 1);
cout << x[i];
}
else if (b[i][j] == 2)
{
LCS(b, x, i - 1, j);
}
else
{
LCS(b, x, i, j - 1);
}
}
int main()
{
int xn, yn;
while (cin >> xn >> yn)
{
x[100] = y[100] = dp[100][100] = b[100][100] = { 0 };
for (int i = 1; i <= xn; i++)
{
cin >> x[i];
}
for (int i = 1; i <= yn; i++)
{
cin >> y[i];
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
if (x[i] == y[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else
{
if (dp[i - 1][j] >= dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
b[i][j] = 2;
}
else
{
dp[i][j] = dp[i][j - 1];
b[i][j] = 3;
}
}
}
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
cout << dp[i][j] << ' ';
}
cout << endl;
}
cout << "最长公共子序列长度为:" << dp[xn][yn] << endl;
cout << "最长公共子序列之一为";
LCS(b, x, xn, yn);
cout << endl;
}
return 0;
}
输出结果:
3,输出所有最长公共子序列(看了几下别人的文章,然后自己写了下,发现虽然能输出所有符合要求的,但是不知道怎么去重,若有大神知道,请告诉下小弟,小弟万分感激)
#include<iostream>
using namespace std;
int x[100], y[100], dp[100][100], b[100][100], result[101];
int n = 0;
//n用于保存解的个数,result数组用于保存解。
void LCS(int b[100][100], int x[], int i, int j, int current_len,int lcs_max_len)
{
if (i == 0 || j == 0)
{
for (int k = 0; k < lcs_max_len;k++)
{
cout << result[k];
}
cout << endl;
n++;
return;
}
if (b[i][j] == 1)
{
current_len--;
result[current_len] = x[i];
LCS(b, x, i - 1, j - 1, current_len, lcs_max_len);
}
else if (b[i][j] == 2)
{
LCS(b, x, i - 1, j , current_len, lcs_max_len);
}
else
{
if (b[i][j] == 3)
{
LCS(b, x, i , j - 1, current_len, lcs_max_len);
}
else
{
LCS(b, x, i , j - 1, current_len, lcs_max_len);
LCS(b, x, i - 1, j , current_len, lcs_max_len);
}
}
}
int main()
{
int xn, yn;
while (cin >> xn >> yn)
{
x[100] = y[100] = dp[100][100] = b[100][100] = { 0 };
for (int i = 0; i < 100; i++)
{
dp[i][0] = dp[0][i] = 0;
}
for (int i = 1; i <= xn; i++)
{
cin >> x[i];
}
for (int i = 1; i <= yn; i++)
{
cin >> y[i];
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
if (x[i] == y[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else
{
if (dp[i - 1][j] > dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
b[i][j] = 2;
}
else if (dp[i - 1][j]<dp[i][j-1])
{
dp[i][j] = dp[i][j - 1];
b[i][j] = 3;
}
else
{
dp[i][j] = dp[i][j - 1]; //或者dp[i][j]=dp[i-1][j];
b[i][j] = 4;
}
}
}
}
for (int i = 1; i <= xn; i++)
{
for (int j = 1; j <= yn; j++)
{
cout << dp[i][j] << ' ';
}
cout << endl;
}
cout << "最长公共子序列长度为:" << dp[xn][yn] << endl;
{
if (dp[xn][yn] == 0)//如果不存在公共子序列就退出。
{
continue;
}
}
cout << "最长公共子序列为"<<endl;
LCS(b, x, xn, yn,dp[xn][yn],dp[xn][yn]);
cout << "共有" << n << "种";
cout << endl;
}
return 0;
}
输出结果:(谁知道怎么去重的告诉小弟一下,万分感激)
——————————结束——————————————
由于仅仅学了半年软件开发,所以代码不是特别规范,也不是很简洁,很多东西都是看了别人的文章才能写出来
最后附上给我启发的文章地址:http://blog.chinaunix.net/uid-26548237-id-3374211.html (感谢大神的文章,学习了好多)