最长公共子序列

本文详细介绍了如何通过动态规划解决最长公共子序列问题,并提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

给定两个字符串s1s2…sns_1 s_2…s_ns1s2snt1t2…tmt_1 t_2…t_mt1t2tm。求这两个字符串的最长的公共子序列。字符串s1s2…sns_1 s_2…s_ns1s2sn的子序列指可以表示为si1si2…sim(i1&lt;i2&lt;⋯&lt;im)s_{i_1} s_{i_2}…s_{i_m} (i_1&lt;i_2&lt;⋯&lt;i_m)si1si2sim(i1<i2<<im)的序列。

解析

  • 这个问题就是著名的最长公共子序列(LCS)问题,使用下面递推DP进行求解:
    • dp数组的含义:dp[i][j]=s1s2…sidp[i][j]= s_1 s_2…s_idp[i][j]=s1s2sit1t2…tjt_1 t_2…t_jt1t2tj的最长公共子序列的长度。
    • 现在我们计算dp[i+1][j+1]dp[i+1][j+1]dp[i+1][j+1],即s1s2…si+1s_1 s_2…s_{i+1}s1s2si+1t1t2…tj+1t_1 t_2…t_{j+1}t1t2tj+1的最长公共子序列的长度,有两种可能:
      • 第一种:s(i+1)=t(j+1)s_(i+1)=t_(j+1)s(i+1)=t(j+1):那么dp[i+1][j+1]= dp[i][j]+1
      • 第二种:si+1!=tj+1s_{i+1} != t_{j+1}si+1!=tj+1:那么dp[i+1][j+1]应该是dp[i+1][j]或者dp[i][j+1]的最大者。
    • 公式总结如下:dp[i+1][j+1]={dp[i][j]+1,s(i+1)=t(j+1)max⁡(dp[i+1][j],dp[i][j+1]),s(i+1)!=t(j+1))dp[i+1][j+1]=\begin{cases} dp[i][j]+1,&amp; s_(i+1)=t_(j+1) \\ max⁡(dp[i+1][j],dp[i][j+1]) ,&amp; s_(i+1)!=t_(j+1) ) \end{cases}dp[i+1][j+1]={dp[i][j]+1,max(dp[i+1][j],dp[i][j+1]),s(i+1)=t(j+1)s(i+1)!=t(j+1))
    • 由上面的公式可知,只有dp[i+1][j]和dp[i][j+1]已经计算出来就可以求出dp[i+1][j+1],即只要当前单元的上面一个单元和左边一个单元已知就可以求出当前的单元。
    • 递推的初始条件:dp[0−n][0]=dp[0][0−m]=0dp[0-n][0]=dp[0][0-m]=0dp[0n][0]=dp[0][0m]=0
    • 组后我们的结果在dp[n][m]里面。我们只要将dp数组中的每个元素都填满就可以计算出dp[n][m],故时间复杂度为O(nm)O(nm)O(nm)

代码:

#include <iostream>

using namespace std;
#define Max_n 1005
#define Max_m 1005

int n,m;
char s[Max_n],t[Max_m];
int dp[Max_n][Max_m];
//初始化
void initialize(int n,int m){
    for(int i=0;i<=n;i++)
        dp[i][0]=0;
    for(int j=0;j<=m;j++)
        dp[0][j]=0;
}
//递推求整个dp数组
void solve(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i]==t[j]){
                dp[i][j]=dp[i-1][j-1]+1;
            }
            else{
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值