动态规划求最长公共子序列和子序列具体是什么

**子序列与子串是两种不同的概念,千万不要混淆
给定字符串"tzjnbblmp";

子串是tzj,bbln等,子串是连在一起的

子序列是 tjn,nlmp等,但是子序列中的字符在字符串中不一定是连在一起的。
但是顺序在原串是不可颠倒的,比如pml既不是子序列,也不是子串
**
回到正文

什么是最长公共子序列
就是两个字符串的最长的公共的子序列
例如s1=“wxhnwq”,s2=“xppwyq”
最长子序列就是"xwq"

我们这样很容易看出来,但是计算机怎么知道呐,
动态规划吧;
设dp[i][j]表示长度为i的字符串与长度为j的字符串的最长的公共子序列
我们分两种情况
1.s1[i]==s2[j],我们就转移方程,dp[i][j]=dp[i-1][j-1]+1;意思是,以s1[i],s2[j]结尾的字符串的最大长度,肯定是前面的,在加上新加入的;
2.s1[i]!=s2[j],dp[i][j]=max(dp[i-1][j],dp[i][j-1];意思是,我们选择(长度为i与j-1)与(长度为i-1与j)的大的一个
我们递归求子序列是什么,在转移方程的同时,标记这一步是由i-1,j-1
还是i,j-1
还是i-1,j
来的

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6;
typedef long long ll;
int dp[1000][1000];
int vis[1001][1001];
char a[100];
char b[100];
void lcslength(int n,int m)
{
    
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
    {
    
    
        if(a[i]==b[j])
        {
    
    
            dp[i][j]=dp[i-1][j-1]+1;
            vis[i][j]=1;

        }
        else if(dp[i-1][j]>dp[i][j-1])
        {
    
    
            dp[i][j]=dp[i-1][j];
            vis[i][j]=2;
        }
        else if(dp[i-1][j]<=dp[i][j-1])
        {
    
    
            dp[i][j]=dp[i][j-1];
            vis[i][j]=3;
        }
    }
}
void lcs(int n,int m)
{
    
    
    if(n==0 || m==0)
        return;
    if(vis[n][m]==1)
        lcs(n-1,m-1),cout<<a[n]<<" ";
    if(vis[n][m]==2)
        lcs(n-1,m);
    if(vis[n][m]==3)
        lcs(n,m-1);
}
int main()
{
    
    
  string s1,s2;
   cin>>s1>>s2;
   int n=s1.length();
   int m=s2.length();
   for(int i=1;i<=n;i++)
      a[i]=s1[i-1];
   for(int i=1;i<=m;i++)
      b[i]=s2[i-1];
   lcslength(n,m);
   cout<<dp[n][m]<<endl;
  lcs(n,m);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43634564/article/details/109271258