最长子序列/串问题

子序列与子串

序列:可以不连续
子串:联系

###最长公共子序列

  • LCS

两个数组

  • Array[][],计算长度,
    A r r a y [ i ] [ j ] = { m a x ( A r r a y [ i ] [ j − 1 ] , A r r a y [ i − 1 ] [ j ] )    ;   X i ! = Y j A r r a y [ i − 1 ] [ j − 1 ] + 1    ;   X i = = Y j 0    ;   i = = 0 ∣ ∣ j = = 0    第 一 列 / 行 初 始 为 0 Array[i][j]= \begin{cases} max(Array[i][j-1],Array[i-1][j]) ~~;~ X_i!=Y_j\\ Array[i-1][j-1]+1~~;~X_i==Y_j \\ 0~~;~i==0 || j==0~~第一列/行初始为0 \end{cases} Array[i][j]=max(Array[i][j1],Array[i1][j])  ; Xi!=YjArray[i1][j1]+1  ; Xi==Yj0  ; i==0j==0  /0
  • B[][] ,记录路径,是逆序的
    B [ i ] [ j ] = { 1    ;   X i = = Y j     往 左 上 走 2    ;   A r r a y [ i ] [ j − 1 ] > = A r r a y [ i − 1 ] [ j ]     往 上 走 3    ;   A r r a y [ i ] [ j − 1 ] < A r r a y [ i − 1 ] [ j ]        往 左 走 0    ;   i = = 0 ∣ ∣ j = = 0    第 一 列 / 行 初 始 为 0 B[i][j]= \begin{cases} 1~~;~X_i==Y_j ~~~{\small}往左上走\\ 2~~;~Array[i][j-1]>=Array[i-1][j]~~~{\small}往上走\\ 3~~;~Array[i][j-1]<Array[i-1][j]~~~~~~{\small}往左走\\ 0~~;~i==0 || j==0~~第一列/行初始为0 \end{cases} B[i][j]=1  ; Xi==Yj   2  ; Array[i][j1]>=Array[i1][j]   3  ; Array[i][j1]<Array[i1][j]      0  ; i==0j==0  /0

路径
从最后遍历b[][]直到b[i][j]==0;
B [ i ] [ j ] = { 1    ;   s + = s 1 [ i − 1 ] ; i − − , j − − ;     往 左 上 走 2    ;   j − −     往 上 走 3    ;   i − −        往 左 走 0    ;   结 束 B[i][j]= \begin{cases} 1~~;~s+=s1[i-1];i--,j--;~~~{\small}往左上走\\ 2~~;~j--~~~{\small}往上走\\ 3~~;~i--~~~~~~{\small}往左走\\ 0~~;~结束 \end{cases} B[i][j]=1  ; s+=s1[i1];i,j;   2  ; j   3  ; i      0  ; 
逆序:reverse(s.begin(),s.end());

#include<iostream>
#include<algorithm>
#include<vector>
//#include <bits/stdc++.h> 
using namespace std;

//定义一个足够大的数组
#define MAX_size 10
//子序列
void output(int a[][MAX_size], int ilen, int jlen);
int main()
{	
	//定义两个字符串
	string s1="abccd", s2="accd";
	//定义两个数组,一个是dp[][]计算长度,另一个用于记录路径,逆
	int Array[MAX_size][MAX_size];
	int B[MAX_size][MAX_size];
	memset(Array,0,sizeof(Array));
	memset(B,0,sizeof(B));
	
	//i==0 || j==0直接为0,不用管
	int i = 1, j = 1;
	while (j<=s2.length())
	{
		i = 1;
		while (i<=s1.length())
		{
		//	cout << "s1" << s1[i - 1] << " s2 " << s2[j - 1] << endl;
			if (s1[i-1] == s2[j-1])
			{
				Array[i][j] = Array[i - 1][j - 1] + 1;
				B[i][j] =1;//往左上走
			}
			else
			{
				if (Array[i][j - 1] >= Array[i - 1][j])
				{
					Array[i][j] = Array[i][j - 1];
					B[i][j] = 2;//往上走
				}
				else
				{
					Array[i][j] = Array[i - 1][j];
					B[i][j] = 3;
				}
				
			}
			i++;
		}
		j++;
	}
	
	output(Array, s1.length(), s2.length());

	//往后走B[][],得到序列
	i = s1.length(); j = s2.length();
	string s="";//放入反序的子序列
	while (B[i][j] != 0)
	{
		switch (B[i][j])
		{
		case 0:break;
		case 1:
			s += s1[i-1];//或者s2[j],两个是一样的
			cout << s1[i-1];
			i -= 1;
			j -= 1;
			break;
		case 2:
			//往上走
			j -= 1;
			break;
		case 3:
			//往左走
			i -= 1;
			break;
		}
	}
	//逆序函数
	reverse(s.begin(), s.end());
	cout << "/n长度"<< Array[s1.length() - 1][s2.length() - 1] << endl;
	cout << s << endl;
	system("pause");
	return 0;
}
//输出二维数组的内容,看成一位数组
void output(int a[][MAX_size] , int ilen, int jlen)
{
	cout << "Array" << endl;

	for (int j = 0; j <=jlen; j++)
	{
		for (int i = 0; i <= ilen; i++)
		{
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}

最长公共子串

与子序列的区别是连续;
不相等时,Array[i][j]直接为0就可以了
只要一个数组,max链而且连续,往左上走;
记录长度max和它的位置(三个数据)。

  • Array[][],计算长度,
    A r r a y [ i ] [ j ] = { 0    ;   i = = 0 ∣ ∣ j = = 0    第 一 列 / 行 初 始 为 0 0    ;   X i ! = Y j A r r a y [ i − 1 ] [ j − 1 ] + 1    ;   X i = = Y j Array[i][j]= \begin{cases} 0~~;~i==0 || j==0~~第一列/行初始为0\\ 0 ~~;~ X_i!=Y_j\\ Array[i-1][j-1]+1~~;~X_i==Y_j \\ \end{cases} Array[i][j]=0  ; i==0j==0  /00  ; Xi!=YjArray[i1][j1]+1  ; Xi==Yj
//find_sonstr(a,s1,s2);
void find_sonstr(int Array[][MAX_size],string s1,string s2)
{
    int MAX_num = 0, MAX_I = 0, MAX_J = 0;
    int i = 1, j = 1;
	while (j<=s2.length())
	{
		i = 1;
		while (i<=s1.length())
		{
		//	cout << "s1" << s1[i - 1] << " s2 " << s2[j - 1] << endl;
			if (s1[i-1] == s2[j-1])
			{
				Array[i][j] = Array[i - 1][j - 1] + 1;


				//判断上一个是不是
				if ( MAX_num < Array[i][j])
				{
					MAX_num = Array[i][j];
					MAX_I = i;
					MAX_J = j;
				}
			}
			else
			{
				Array[i][j] = 0;
			}
			i++;
		}
		j++;
	}

	//往后走B[][],得到序列
	i = MAX_I; j = MAX_J;
	string s="";//放入反序的子序列
	while (Array[i][j] != 0)
	{
		s += s1[i-1];//或者s2[j],两个是一样的
		cout << s1[i-1];
		i -= 1;
		j -= 1;
	}
	//逆序函数
	reverse(s.begin(), s.end());
	cout << "/n len  "<<MAX_num << endl;
	cout << s << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值