最长公共子序列(求出长度并且输出子序列)

动态规划思想:把一个大的问题分解成若干个子问题,求出子问题后,然后回溯求出大的问题。

分析:给定两个字符串,假设为“a0,a1,a2....an”和"b0,b1,b2...bm",要求出两个字符串的最长公共子序列,我们先把大问题分成小问题,举个例子吧!

假设“c0,c1,c2...ck”为它们的最长公共子序列。第一种:an=bm,则“c0,c1,c2...c(k-1)”为“a0,a1,a2...a(n-1)”和"b0,b1,b2...b(m-1)"的最长公共子序列;

第二种:an!=bm并且an!=ck则“c0,c1,c2...ck”为"a0,a1,a2....a(n-1)"和"b0,b1,b2...bm"的最长公共子序列;第三种:an!=bm并且bm!=ck,

则“c0,c1,c2...ck”为"a0,a1,a2....an"和"b0,b1,b2...b(m-1)"的最长公共子序列.

求解:
引进一个二维数组dp[][],用dp[i][j]记录a[i]与b[j] 的LCS 的长度,flag[i][j]记录dp[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。

我们是自底向上进行递推计算,那么在计算dp[i,j]之前,dp[i-1][j-1],dp[i-1][j]与dp[i][j-1]均已计算出来。此时我们根据a[i] = b[j]还是a[i] != b[j],就可以计算出dp[i][j]。

问题的递归式写成:recursive formula

回溯输出最长公共子序列过程:

flow

算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m * n)。

代码实现:

复制代码

#include<stdio.h>
#include<string.h>
char a[1000],b[1000];
int  dp[1000][1000],flag[1000][1000],len1,len2,i,j;
int lsc()//求最长公共子序列的长度并且记录路劲
{
   for(i=0;i<=len1;i++)
     dp[i][0]=0;
   for(j=0;j<=len2;j++)
     dp[0][j]=0;
   for(i=1;i<=len1;i++)
     for(j=1;j<=len2;j++)
     {
         if(a[i-1]==b[j-1])
         {
            dp[i][j]=dp[i-1][j-1]+1;
            flag[i][j]=0;
         }
         else
         {
            if(dp[i-1][j]>=dp[i][j-1])
            {
              dp[i][j]=dp[i-1][j];
              flag[i][j]=1;
            }
            else
            {
              dp[i][j]=dp[i][j-1];
              flag[i][j]=2;
            }
         }
    }
    return dp[len1][len2];
}


void printflsc(int x,int y)//回溯输出最长公共子序列
{
  if(x==0||y==0)
   return;
  if(flag[x][y]==0)
  {
     printflsc(x-1,y-1);
     printf("%c ",a[x-1]);
  }
  else if(flag[x][y]==1)
     printflsc(x-1,y);
  else
     printflsc(x,y-1);
}


int main()
{
  int t;
  while(scanf("%s%s",a,b)!=EOF)
  {
     len1=strlen(a);
     len2=strlen(b);
     t=lsc();
     printf("%d\n",t);
     if(t)
     {
       printflsc(len1,len2);
       printf("\n");
     }
  }
  return 0;
}


复制代码

 

posted on   后端bug开发工程师  阅读(1963)  评论(0编辑  收藏  举报

编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!

导航

< 2013年3月 >
24 25 26 27 28 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 1 2 3 4 5 6
点击右上角即可分享
微信分享提示