最长公共子序列:DP

思路:s1[i]与s2[j]是否匹配,dp[i+1][j+1]:以s[i]与s[j]为末尾匹配的最长公共序列长度, 由于要输出序列,所以得到公共子序列长度后,需要从后往前拼接

  • ①是:dp[i+1][j+1]=dp[i][j]+1;都往前一个字符,再匹配
  • ②否:dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]) s1往前一个字符,再匹配 或者 s2往前一个字符,再匹配
#include<iostream>
#include<string>
using namespace std;

const int maxn=5001;

string s1,s2;
int dp[maxn][maxn];

string longest(int m1,int m2){
    string ans;
    for(int i=0;i<=m1;i++)dp[i][0]=0;//初始化(边界为0)
    for(int i=0;i<=m2;i++)dp[0][i]=0;
    
    for(int i=0;i<m1;i++){
        for(int j=0;j<m2;j++){
            if(s1[i]==s2[j])dp[i+1][j+1]=dp[i][j]+1;
            else{
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
            }
        }
    }
    
    if(dp[m1][m2]==0){//公共子序列的长度为空
        ans="-1";
        return ans;
    }
    
    int posi=m1-1,posj=m2-1;
    while(posi>=0&&posj>=0){//逆向拼接
        if(s1[posi]==s2[posj]){//末位匹配
            ans=s1[posi]+ans;
            posi--;
            posj--;
        }
        else if(dp[posi][posj+1]>dp[posi+1][posj]){
            posi--;
        }
        else posj--;
    }
    return ans;
}

int main(){
    while(cin>>s1>>s2){
        int m1=s1.size();
        int m2=s2.size();
        cout<<longest(m1,m2)<<endl;
    }
    return 0;
}