最长公共子序列(动态规划)
最长公共子串问题(动态规划)
问题描述
1.最长公共子序列的结构
解释:
(1)X和Y的末尾元素相同则,公共子串一定包含末尾元素,所以公共子串是X和Y的公共子串
(2)X和Y的末尾元素不同,Y末尾元素和最长公共子序列的末尾元素相同,说明X要遍历全部,而X末尾元素无需考虑,所以最长公共子序列为X和Y的前M-1个元素
(3)X和Y的末尾元素不同,X末尾元素和最长公共子序列的末尾元素相同,说明X要遍历全部,而Y末尾元素无需考虑,所以最长公共子序列为X和Y的前N-1个元素
2.子问题的递归结构
3.计算最优值
4.代码实现
int lcs(int m, int n, string x, string y, int** c, int** b)
{
//m为字符串x的长度 n为字符串y的长度
//c为c[i][j]数组,表示i-1长度x,j-1长度的y的最长公共子序列的长度
//b记录路劲,1为x,y都增长,2为x增长,3为y增长
//初始化 如何一个字符串长度为0,则公共子串长度为0
int i, j;
for (i = 0; i <= m; i++) {
c[i][0] = 0;//y为空串
b[i][0] = 0;
}
for (i = 0; i <= n; i++)
{
c[0][i] = 0;//x为空串
b[0][i] = 0;
}
for (i = 1; i <= m; i++) {
for (j = 1; j <= n; j++) {
if (x[i - 1] == y[j - 1])//第一种情况,末尾相同
{
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else if (c[i - 1][j] >= c[i][j - 1]) {//第二种情况
c[i][j] = c[i - 1][j];
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j - 1];//第三种情况
b[i][j] = 3;
}
}
}
for (i = 0; i <= m; i++)//输出c矩阵查看
{
for (j = 0; j <=n; j++) {
cout << c[i][j] << ' ';
}
cout << endl;
}
return c[m - 1][n - 1];
}
测试样例
int main()
{
int** c, **b;
c = new int* [10];
b = new int* [10];
for (int i = 0; i < 10; i++)
{
c[i] = new int[10]{};
b[i] = new int[10]{};
}
string x = "abcbdabe";
string y = "bdcabae";
cout << lcs(8, 7, x, y, c, b);
}
测试结果
这里因为还有记录路径,所以写了3种情况,如果不记录路径的话只需要2种情况相同和不同,相同的情况在前一种基础上加1,不同的情况就是x小,y小2种情况中取较大者,修改关键代码图下
for (i = 1; i < m; i++) {
for (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-1][j],c[i][j-1]);
}
}
}
求出路径
上面的b矩阵记录了数组xy不同长度下的情况。我们知道情况1是x和y字母相同c[i][j] = c[i - 1][j - 1]+1,x,y都增加,符合公共子串。2 是c[i][j] = c[i - 1][j],字符串x的长度增加,是向下。3是c[i][j] = c[i][j - 1],是y字符串增加,向右。所以我们只需要从i=1,j=1开始,按照遇到1 执行i–;j–。遇到2执行i–;遇到3执行j–;遍历完矩阵b就可以得到最终的最长公共子序列
完整代码
int lcs(int m, int n, string x, string y, int** c, int** b)
{
//m为字符串x的长度 n为字符串y的长度
//c为c[i][j]数组,表示i-1长度x,j-1长度的y的最长公共子序列的长度
//b记录路劲,1为x,y都增长,2为x增长,3为y增长
//初始化 如何一个字符串长度为0,则公共子串长度为0
int i, j;
for (i = 0; i <= m; i++) {
c[i][0] = 0;//y为空串
b[i][0] = 0;
}
for (i = 0; i <= n; i++)
{
c[0][i] = 0;//x为空串
b[0][i] = 0;
}
for (i = 1; i <= m; i++) {
for (j = 1; j <= n; j++) {
if (x[i - 1] == y[j - 1])//第一种情况,末尾相同
{
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else if (c[i - 1][j] >= c[i][j - 1]) {//第二种情况
c[i][j] = c[i - 1][j];
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j - 1];//第三种情况
b[i][j] = 3;
}
}
}
for (i = 0; i <= m; i++)//输出c矩阵查看
{
for (j = 0; j <=n; j++) {
cout << c[i][j] << ' ';
}
cout << endl;
}
cout << endl;
for (i = 0; i <= m; i++)//输出c矩阵查看
{
for (j = 0; j <= n; j++) {
cout << b[i][j] << ' ';
}
cout << endl;
}
cout << endl;
i--; j--;
while (i > 0 && j > 0)
{
if (b[i][j] == 1) { cout << x[i-1]; i--; j--; }
else if (b[i][j] == 2) { i--; }
else { j--; }
}
cout << endl;
return c[m - 1][n - 1];
}
结果
本文来自博客园,作者:墨镜一戴谁也不爱,转载请注明原文链接:https://www.cnblogs.com/hnuzmh/p/16196568.html