最长公共子序列

一、题目
1、来源

力扣题号1143:https://leetcode-cn.com/problems/longest-common-subsequence/

2、题目描述

给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

二、解题思路
1、dp定义

这是一个二维DP问题,需要求解的是两个字符串最长公共子序列的长度,一般我们是可以直接将dp[i][j]定义为题目求解的答案(也有部分情况还需要对dp进行处理),所以这里我们定义dp[i][j]为字符串text1[0...i]与字符串text2[0...j]的最长公共子序列

2、初始状态

两个字符串分别为text1text2,假设text1="abc",text2="de",则dp形如:

行为text1,列为text2“”de
“”
a
b
c

两个空串分别表示text1为空和text2为空。
(1) 当text1为空时,text2的任意一个字符与text1的公共子序列都为空,即dp[0][j]=0, j>=0 && j<=text2.size(),j取等号是因为我们表格中考虑了空串,所以dp的行为text1.size()+1,列为text2.size()+1
(2) 当text2为空时,有dp[i][0]=0, i>=0 && i<=text1.size(),理由同上

3、转移方程

(1) 当text1[i]=text2[j]时,则有dp[i][j]=dp[i-1][j-1]+1

text1ab...cdtext1(i)
text2db...cdtext2(j)

可以看到text1[i]text2[j]的最长公共子序列为text1[i-1]text2[j-1]的最长公共子序列+text1[i]或text2[j]
(2)当text1[i]!=text2[j]时,则分为三种情况:
①通过text1[i-1]text2[j-1]计算,即dp[i][j]=dp[i-1][j-1]

text1ab...cdtext1(i)
text2db...cdtext2(j)

②通过text1[i-1]text2[j]计算,即dp[i][j]=dp[i-1][j]

text1ab...cdtext1(i)
text2db...cdtext2(j)

③通过text1[i]text2[j-1]计算,即dp[i][j]=dp[i][j-1]

text1ab...cdtext1(i)
text2db...cdtext2(j)

从上面三种情况可以看到,(text1[i-1],text2[j-1])的最长公共子序列不可能比(text1[i-1],text2[j])或者(text1[i],text2[j-1])的长。所以dp[i][j]=max(dp[i-1][j],dp[i][j-1])

三、C++源码
int longestCommonSubsequence(string text1, string text2) {
        int len1=text1.size();
        int len2=text2.size();
        int dp[len1+1][len2+1]={0}; // 行为text1的长度
        for(int i=0;i<=len1;i++) // 类比text2为空串的情况(即列为空串)
            dp[i][0]=0; 
        for(int j=0;j<=len2;j++) // 类型text1为空串的情况,即行为空串
            dp[0][j]=0;
        for(int i=1;i<=len1;i++){
            for(int j=1;j<=len2;j++){ // 将text1的每个字符逐个与text2比较
                if(text1[i-1]==text2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]); // dp[i-1][j-1]的长度始终比这两个短
            }
        }
        return dp[len1][len2];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值