最长公共子序列和最长公共子串

                                   最长公共子序列和最长公共子串

最长公共子序列:

最长公共子串:


最长公共子序列:

给定一个序列X=<x1,x2,x3,x4...,xm>,另一个序列Z=<z1,z2,z3,z4...,zk>,若存在一个严格递增X的下标序列<i1,i2,i3,...,ik>对所有的1,2,3,...,k,都满足x(ik)=zk,则称ZX的子序列

比如Z=<B,C,D,B>X=<A,B,C,B,D,A,B>的子序列

对于如下的两个字符串 她的最长公共子序列是2345.

       string s1 = "1AB2345CD";

       string s2 = "2345EF";

最长公共子序列的长度是固定的,但是得到的子序列不一定是一样的。

例如:

S1=2FE45      S2=24EF5    长度为3 但是 子序列可以是 245  也可以是2F5

 

理解了上诉的题目,我们可以知道,对于S1,S2的到的公共子序列S3可以得到如下的定义:

我们假设S3就是我们得到的那个子序列,n是s1的长度,m是s2的长度,k是s3的长度

1.如果 s1[n]=s2[m] 且s3[k]=s1[n]=s2[m],那么s3[k]一定是s2[m]和s1[n] 得到的子序列

2.如果 s1[n]!=s2[m] 且s3[k]!=s1[n]  那么s3[k] 一定是s2[m]和s1[n-1] 得到的子序列

2.如果 s1[n]!=s2[m] 且s3[k]!=s2[m]  那么s3[k] 一定是s2[m-1]和s1[n] 得到的子序列

如此循环,直到我们遍历完整个字符串,我们就可以得到结果。

因此我们就可以写出如下的递推方程:

根据如此,我们就可以写出如下的代码。

int a = 0;
int LSClength(string str1, string str2, int i, int j)
{
	if (i<0||j<0)
		return 0;
	a++;
	if (str1[i] == str2[j])
	{
		return LSClength(str1, str2, i - 1, j - 1) + 1;
	}
	return max(LSClength(str1, str2, i, j - 1), LSClength(str1, str2, i-1, j ));
}

对于a,和本题没有关系,只是为了比较统计一下,一共计算了多少次:

得到 结果为4,一共计算了 1946次。


但是对于动态规划来说,不仅要找到递推方程,更要用二维数组来保存,这样可以减少重复计算的过程,如下就是填表的过程:

首先我们先申请一个二维数组,将横坐标等于0,和纵坐标等于0的先空下来,是因为方便计算,边界值更好处理。

根据我们的递推方程可以得到如下的填写规则:

首先我们从横坐标为1的哪一行开始填写,先比较进行比较,如果不相等, 因此这个位置填写的一个是 左边和上边更大的那个值,如果相等的时候,我们就填写的是左上角的值在+1。

这样我们可以写出如下的代码:

int b = 0;
int LSClength(string str1, string str2, int i, int j, vector<vector<int>> &vec)
{
	b++;
	if (i < 0 || j < 0)
		return 0;
	if (vec[i][j]>0)
		return vec[i][j];
	if (str1[i] == str2[j])
		vec[i ][j ] = LSClength(str1, str2, i - 1, j - 1, vec) + 1;
	else
		vec[i ][j] = max(LSClength(str1, str2, i - 1, j, vec), LSClength(str1, str2, i, j - 1, vec));
	return vec[i ][j];
}

b的作用和上面的a是一样的,得到了如下的结果:

得到的结果也是 4,计算了469次,并且得到了填好表的数组。


这时候,我们就可以得到我们的答案了,但是如果我们不仅需要得到长度,还想要得到字符串,这时候,我们就需要在定义一个数组,如果,当我们的 s1[n]=s2[m]的时候,就填写1,如果不相等的时候,左移就是2,上移就是3得到如下的数组。

如此我们就可以得到结果。

/LSC 最长公共子序列
void print_vector(vector<vector<int>> &c)   //打印数组
{
	for (int i = 0; i<c.size(); i++)
	{
		for (int j = 0; j < c[i].size(); j++)
		{
			cout << setw(5) << c[i][j] << " ";
		}
		cout << endl;
	}
}
int LSClength(string str1, string str2, int i, int j, vector<vector<int>> &vec, vector<vector<int>> &vrc)   //递归求长度的
{
	if (i < 0 || j < 0)
		return 0;
	if (vec[i][j] > 0) return vec[i][j];
	else
	{
		if (str1[i] == str2[j])
		{
			vec[i][j] = LSClength(str1, str2, i - 1, j - 1, vec,vrc) + 1;
			vrc[i][j] = 1;
		}
		else
		{
			int n1 = LSClength(str1, str2, i - 1, j, vec, vrc);
			int n2 = LSClength(str1, str2, i, j - 1, vec, vrc);
			if (n1 > n2)
			{
				vec[i][j] = n1;
				vrc[i][j] = 2;
			}
			else
			{
				vec[i][j] = n2;
				vrc[i][j] = 3;
			}
		}

	}
	return vec[i][j];
}

int NiceLSClength(string str1, string str2, int i, int j, vector<vector<int>> &vec, vector<vector<int>> &vrc)  //非递归求长度
{
	if (str1[0] == str2[0])
	{
		vec[0][0] = 1;
		vrc[0][0] = 1;
	}
	for (int a = 1; a <= i; a++)
	{
		if (str1[a] == str2[0])
		{
			vec[a][0] = 1;
			vrc[a][0] = 1;
		}
		else
		{
			vec[a][0] = vec[a - 1][0];
			vrc[a][0] = 2;
		}
	}
	for (int b = 1; b <= j; b++)
	{
		if (str1[0] == str2[b])
		{
			vec[0][b] = 1;
			vrc[0][b] = 1;
		}
		else
		{
			vec[0][b] = vec[0][b - 1];
			vrc[0][b] = 3;
		}
	}
	for (int a = 1; a <= i; a++)
	{
		for (int b = 1; b <= j; b++)
		{
			if (str1[a] == str2[b])
			{
				vec[a][b] = vec[a - 1][b - 1] + 1;
				vrc[a][b] = 1;
			}
			else
			{
				if (vec[a - 1][b] > vec[a][b - 1])
				{
					vec[a][b] = vec[a - 1][b];
					vrc[a][b] = 2;
				}
				else
				{
					vec[a][b] = vec[a][b - 1];
					vrc[a][b] = 3;
				}
			}
		}
	}
	return vec[i][j];
}
void print_stack(stack<char> &st)
{
	while (!st.empty())
	{
		cout << st.top();
		st.pop();
	}
	cout << endl;
	return;
}

void Stanck_vector(int i, int j, stack<char>&st, string X, vector<vector<int>> &s)  //通过数组得到 子串的, 将其放进栈里面
{
	if (i<0 || j<0)
	{
		print_stack(st);
		return;
	}
	int pos = s[i][j];

	if (pos == 1)
	{
		st.push(X[i]);
		//cout << X[i];
		Stanck_vector(i - 1, j - 1, st, X, s);
	}
	else
	{
		if (pos == 2)
		{
			Stanck_vector(i - 1, j, st, X, s);
		}
		else
		{
			Stanck_vector(i, j - 1, st, X, s);
		}
	}
}

 

 



最长公共子串:

有两个字符串,这两个字符串可能会存在公共的部分,如字符串"abcdef" 和字符串"defg",这两个字符串之间有共同的字符串,“d”,“e”,“f”,“de”,“ef”,“def” 等。最长的公共子串就是"def"。

和上上题不同的是,我们的子串在原字符串中必须是连续的。

其他的和上题是一样的,我们很快很能得出如下的递推方程:

得到的代码如下:

void print_vector(vector<vector<int>> &c)  //打印数组
{
	for (int i = 0; i<c.size(); i++)
	{
		for (int j = 0; j < c[i].size(); j++)
		{
			cout << setw(5) << c[i][j] << " ";
		}
		cout << endl<<endl;
	}
}
string   LSClength(string s1, string s2, int n1, int n2, vector<vector<int>>& vec) //求子串的
{
	int big = 0;  //最大长度
	int end = 0;  //结束位置
	vec[0][0] = 0;
	for (int i = 1; i <= n1; i++)
	{
		for (int j = 1; j <= n2; j++)
		{
			if (s1[i] == s2[j])
			{
				vec[i][j] = vec[i - 1][j - 1] + 1;
				if (big < vec[i][j])
				{
					big = vec[i][j];
					end = i;
				}
			}
		}
	}
	if (big == 0)
		return "-1";
	string s3 = s1.substr(end - big + 1, big);
	print_vector(vec);
	return s3;
}



string LCS(string str1, string str2)
{
	// write code here
	int n1 = str1.size();
	int n2 = str2.size();
	if (n1 == 0 || n2 == 0)
		return "-1";
	str1 = "#" + str1;
	str2 = "#" + str2;
	vector<vector<int>>vec;
	vec.resize(n1 + 1);
	for (int i = 0; i<n1 + 1; i++)
	{
		vec[i].resize(n2 + 1);
	}
	return LSClength(str1, str2, n1, n2, vec);
	
}


int main()
{
	string s1 = "acbcbcef";
	string s2 = "abcbced";
	cout << LCS(s1, s2) << endl;
	return 0;
}

在这一个中很多的子串,我们需要找到最大的那个。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值