最长公共子序列 动态规划法

基本概念


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;
 } 
以下为运行结果

在这里插入图片描述

以下照片都是在转载的
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值