基本概念
1.子序列(subsequence): 一个特定序列的子序列就是将给定序列中零个或多个元素去掉后得到的结果(不改变元素间相对次序)。例如序列<A,B,C,B,D,A,B>的子序列有:<A,B>、<B,C,A>、<A,B,C,D,A>等。
2.公共子序列(common subsequence): 给定序列X和Y,序列Z是X的子序列,也是Y的子序列,则Z是X和Y的公共子序列。例如X=[A,B,C,B,D,A,B],Y=[B,D,C,A,B,A[,那么序列Z=[B,C,A]为X和Y的公共子序列,其长度为3。但Z不是X和Y的最长公共子序列,而序列[B,C,B,A]和[B,D,A,B]也均为X和Y的最长公共子序列,长度为4,而X和Y不存在长度大于等于5的公共子序列。对于序列[A,B,C]和序列[E,F,G]的公共子序列只有空序列[]。
3.最长公共子序列:给定序列X和Y,从它们的所有公共子序列中选出长度最长的那一个或几个。
下面这个关于X和Y两个序列的表就是根据上面这个公式得到的,从图中可以看出,最长公共子不唯一,可能会有很多个,还有一点就是右下角的数字四就是最长子序列的长度
以下是对最长公共子序列的代码实现
#include<stdio.h>
#include<string.h>
#define N 100
//这里用c[N][N]的矩阵来保存值
char X[N],Y[N],str[N];
int c[N][N],num=0;//自定义了一个N*N的矩阵 ,num是保存长度的全局变量
int lcs_len(char* X,char* Y,int C[][N])
{
int m=strlen(X),n=strlen(Y),i,j;
for(i=0;i<=m;i++)//给第一列赋初值
c[i][0]=0;
for(i=0;i<=n;i++)//给第一行赋初值
c[0][i]=0;
//以下就是执行的填表操作
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(X[i-1]==Y[j-1])//判断第i-1行和Y数组中的字母有没有相同的 ,这里减去1是XY两个数组是从0开始的
c[i][j]=c[i-1][j-1]+1;//这里意思是如果X和Y相等的话,就是直接把左上的数字加1
else if(c[i-1][j]>=c[i][j-1]) //这里主要是判断天这个位置上面的还是左边的额,选取最大的填
c[i][j]=c[i-1][j];
else
c[i][j]=c[i][j-1];
}
}
return c[m][n];//这个c[m][n]里面存储的是个数字
}
上面这个lcs_len就是对C[N][N]的填表操作,是基于上面的公式来进行填表,然后,build_lcs中就可以直接查表,这也是动态规划算法的优点之一
char* build_lcs(char s[],char* X,char* Y)
{
int i=strlen(X),j=strlen(Y);
int k=lcs_len(X,Y,c);
s[k]='\0';//s数字保存的是最大公共子序列
while(k>0)
{
if(c[i][j]==c[i-1][j])
i--;
else if(c[i][j]==c[i][j-1])
j--;
else
{
s[--k]=X[i-1];
i--;
j--;
num++;
}
}
return s;
}
int main()
{
printf("请输入一个小于100的字符串X:");
scanf("%s",&X);
printf("请输入一个小于100的字符串Y:");
scanf("%s",&Y);
printf("Lsc=%s\n",build_lcs(str,X,Y));
printf("最长公共子序列的长度为:%d",num);
getchar();
return 0;
}
以下照片都是在转载的