这是我参与 8 月更文挑战的第 18 天,活动详情查看: 8月更文挑战
定义:
设序列M是序列A(长度为n)和序列B(长度为m)的子序列,且是所有符合同时是序列A和序列B中的子序列中最长的子序列,则序列M就是我们要求解的最长子序列。
应用:
对比两个文章的相似程度。
方法
方法一、枚举法
A有2n个子序列(n个数只有两种选择:取或不取),对每个子序列确定是否为最长的子序列,时间复杂度为O(m2n)。
方法二、动态规划dp
令L[i,j]表示Ai和Bj的最长公共子序列长度,则
设计一个字符串数组,用来保存最长公共子序列,两个整型数组,保存最长公共子序列在字符串A和字符串B中对应的下标.
(1)C++中定义二维数组
//申请空间
int** a2 = new int*[rows];
for(int i=0;i<rows;i++)
a2[i] = new int[columns];
//释放空间
for(int i=0;i<rows;i++)
delete []a2[i];
delete []a2;
#include<iostream>
#include<string>
#include<stack>
using namespace std;
//生成m行n列的二维数组
void LCS(string s1,string s2)
{
int m=s1.length()+1;
int n=s2.length()+1;
int **c;
int **b;
c=new int* [m];
b=new int* [m];
for(int i=0;i<m;i++){
c[i]=new int[n];
b[i]=new int[n];
for(int j=0;j<n;j++)
b[i][j]=0;
}
//无论是第一个字符串长度还是第二个字符串长度为0,最长字符串一律为0
for(int i=0;i<m;i++)
c[i][0]=0;
for(int i=0;i<n;i++)
c[0][i]=0;
for(int i=0;i<m-1;i++)
{
for(int j=0;j<n-1;j++)
{
if(s1[i]==s2[j])
{
c[i+1][j+1]=c[i][j]+1;
b[i+1][j+1]=1;//用1表示箭头↖
}
else if(c[i][j+1]>=c[i+1][j])
{
c[i+1][j+1]=c[i][j+1];
b[i+1][j+1]=2;//2表示箭头↑
}
else
{
c[i+1][j+1]=c[i+1][j];
b[i+1][j+1]=3;//3表示箭头←
}
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cout<<c[i][j]<<' ';
}
cout<<endl;
}
stack<char> same;//存最长公共子序列
stack<int> same1,same2; //存最长公共子序列在字符串1和字符串2中对应的下标,方便显示
for(int i=m-1,j=n-1;i>=0&&j>=0;)
{
if(b[i][j]==1)
{
i--;
j--;
same.push(s1[i]);//或s2[j]
same1.push(i);
same2.push(j);
}
else if(b[i][j]==2)
i--;
else
{
j--;
}
}
cout<<s1<<endl;//输出s1
for(int i=0;i<m && !same1.empty();i++)//输出字符串1的标记
{
if(i==same1.top())
{
cout<<1;
same1.pop();
}
else
{
cout<<' ';
}
}
cout<<endl<<s2<<endl;
for(int i=0;i<n && !same2.empty();i++)
{
if(i==same2.top())
{
cout<<1;
same2.pop();
}
else
{
cout<<' ';
}
}
cout<<endl<<"最长公共子序列为:";
while(!same.empty())
{
cout<<same.top();
same.pop();
}
cout<<endl<<"长度为:"<<c[m-1][n-1]<<endl;
for (int i = 0; i<m; i++)
{
delete [] c[i];
delete [] b[i];
}
delete []c;
delete []b;
}
int main()
{
string s1="ABCPDSFJGODIHJOFDIUSHGD";
string s2="OSDIHGKODGHBLKSJBHKAGHI";
LCS(s1,s2);
system("pause");
return 0;
}