子序列与子串
序列:可以不连续
子串:联系
###最长公共子序列
- 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][j−1],Array[i−1][j]) ; Xi!=YjArray[i−1][j−1]+1 ; Xi==Yj0 ; i==0∣∣j==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][j−1]>=Array[i−1][j] 往上走3 ; Array[i][j−1]<Array[i−1][j] 往左走0 ; i==0∣∣j==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[i−1];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==0∣∣j==0 第一列/行初始为00 ; Xi!=YjArray[i−1][j−1]+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;
}