LCS最长公共子序列

目录

 LCS最长公共子序列的长度

  LCS最长公共子序列

有两个字符串
str1:helloworld    X:X1,X2,....Xn
str2:hlweord        Y:Y1,Y2,....Ym

 LCS最长公共子序列的长度

如果Xn == Ym 
LCS(X[1....n],Y[1...m]) = LCS(x[1...n-1],Y[1....m-1])+1 
如果Xn != Xm
 LCS(X[1....n],Y[1...m]) = max{LCS(x[1...n],Y[1....m-1]), LCS(x[1...n-1],Y[1....m])}
以上边字串为例进行分析如图:

状态转移方程: 

 如果Xn == Ym 
dp(X[1....n],Y[1...m]) = dp(x[1...n-1],Y[1....m-1])+1 
如果Xn != Xm
 dp(X[1....n],Y[1...m]) = max{dp(x[1...n],Y[1....m-1]), dp(x[1...n-1],Y[1....m])}

状态:给定的两个序列的LCS 的长度

dp[n][m]:n表示第一个串的长度,m表示第二个串的长度,n行m列元素的值,记录的就是这两个串的LCS长度

 如上图,递归从后往前进行遍历,回溯时,从前往后,当X[n] == Y[m]的时候,给dp[n][m]+1。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int cnt = 0;//用于代码测试

string str1 = "helloworld";
string str2 = "hlweord";

int **dp = nullptr;
int **path = nullptr;

int LCS01(string X,int n,string Y,int m)
{

	if (n < 0 || m < 0)
	{
		return 0;
	}
	if (dp[n][m] > 0) //已经被求解的子问题
	{
		return dp[n][m];
	}
	cnt++;
	if (X[n] == Y[m])
	{
		dp[n][m] =  LCS01(X, n - 1, Y, m - 1) + 1;
		path[n][m] = 1;
		return dp[n][m];
	}
	else
	{
		int len1 = LCS01(X, n, Y, m - 1);
		int len2 = LCS01(X, n - 1, Y, m);
		if (len1 >= len2)
		{
			dp[n][m] = len1;
			path[n][m] = 2;//往左走
		}
		else
		{
			dp[n][m] = len2;
			path[n][m] = 3;//往右走
		}
		return dp[n][m];
	}
}

int main()
{
	int n = str1.size();
	int m = str2.size();
	dp = new int *[n]; //n 行
	for (int i = 0; i < n; ++i)
	{
		dp[i] = new int[m];//m列
		for (int j = 0; j < m; ++j)
		{
			dp[i][j] = -1;
		}
	}
	path = new int *[n]; //n行
	for (int i = 0; i < n; ++i)
	{
		path[i] = new int[m]();//m列
	}

	int size = LCS01(str1,n-1,str2,m-1);
	cout << "LCS length: " << size << endl;
	cout << "cnt: " << cnt << endl;

	system("pause");
	return 0;
}

结果显示如下:

  LCS最长公共子序列

 

这个思路和我们解决最长公共子序列的长度一样,也是递归回溯,递归从后往前进行遍历,如最长公共子序列的长度的图中线连接的数字就是递归遍历的路线,回溯时,从前往后,打印这条路线上1所对应的值。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int cnt = 0;//用于代码测试

string str1 = "helloworld";
string str2 = "hlweord";

int **dp = nullptr;
int **path = nullptr;

int LCS01(string X,int n,string Y,int m)
{

	if (n < 0 || m < 0)
	{
		return 0;
	}
	if (dp[n][m] > 0) //已经被求解的子问题
	{
		return dp[n][m];
	}
	cnt++;
	if (X[n] == Y[m])
	{
		dp[n][m] =  LCS01(X, n - 1, Y, m - 1) + 1;
		path[n][m] = 1;
		return dp[n][m];
	}
	else
	{
		int len1 = LCS01(X, n, Y, m - 1);
		int len2 = LCS01(X, n - 1, Y, m);
		if (len1 >= len2)
		{
			dp[n][m] = len1;
			path[n][m] = 2;//往左走
		}
		else
		{
			dp[n][m] = len2;
			path[n][m] = 3;//往右走
		}
		return dp[n][m];
	}
}

void backStrace(string str1,int n,int m)
{
	if (n < 0 || m < 0)
	{
		return;
	}
	if (path[n][m] == 1) //走对角线 回溯之后打印这个值
	{
		backStrace(str1, n - 1, m - 1);
		cout << str1[n];
	}
	else
	{
		if (path[n][m] == 2)//往左走 向左递归
		{
			backStrace(str1, n, m - 1);

		}
		else
		{ //path[n][m] == 3  往上走  向上递归
			backStrace(str1, n - 1, m);

		}
	}
}
int main()
{
	int n = str1.size();
	int m = str2.size();
	dp = new int *[n]; //n 行
	for (int i = 0; i < n; ++i)
	{
		dp[i] = new int[m];//m列
		for (int j = 0; j < m; ++j)
		{
			dp[i][j] = -1;
		}
	}
	path = new int *[n]; //n行
	for (int i = 0; i < n; ++i)
	{
		path[i] = new int[m]();//m列
	}

	int size = LCS01(str1,n-1,str2,m-1);

	backStrace(str1, n-1, m-1);
	cout << endl;
	system("pause");
	return 0;
}

结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值