1143. 最长公共子序列——【Leetcode每日刷题】
创始人
2024-06-02 01:48:46
0

1143. 最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。

示例 2:

输入:text1 = “abc”, text2 = “abc”
输出:3
解释:最长公共子序列是 “abc” ,它的长度为 3 。

示例 3:

输入:text1 = “abc”, text2 = “def”
输出:0
解释:两个字符串没有公共子序列,返回 0 。

提示:

  • 1 <= text1.length, text2.length <= 1000
  • text1 和 text2 仅由小写英文字符组成。

思路:(动态规划)

对于两个子序列 S1S1S1 和 S2S2S2,找出它们最长的公共子序列。

定义一个二维数组 dp 用来存储最长公共子序列的长度,其中 dp[i][j] 表示 S1S1S1 的前 i 个字符与 S2S2S2 的前 j 个字符最长公共子序列的长度。考虑 S1iS1_iS1i​与 S2jS2_jS2j​ 值是否相等,分为两种情况:

  • 当 S1i==S2jS1_i == S2_jS1i​==S2j​ 时,那么就能在 S1S1S1 的前 i -1 个字符与 S2S2S2 的前 j -1 个字符最长公共子序列的基础上再加上 S1iS1_iS1i​ 这个值,最长公共子序列长度加 1,即 dp[i][j] = dp[i-1][j-1] + 1。
  • 当 S1i!=S2jS1_i != S2_jS1i​!=S2j​ 时,此时最长公共子序列为 S1S1S1的前 i -1 个字符和 S2 的前 j 个字符最长公共子序列,或者 S1S1S1 的前 i 个字符和 S2S2S2 的前 j -1 个字符最长公共子序列,取它们的最大者,即 dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。

综上,最长公共子序列的 状态转移方程 为:

dp[i][j]={dp[i−1][j−1]+1S1i==S2jmax⁡(dp[i−1][j],dp[i][j−1])S1i<>S2jd p[i][j]=\left\{\begin{array}{rr} d p[i-1][j-1]+1 & S 1_{i}==S 2_{j} \\ \max (d p[i-1][j], d p[i][j-1]) & S 1_{i}<>S 2_{j} \end{array}\right.dp[i][j]={dp[i−1][j−1]+1max(dp[i−1][j],dp[i][j−1])​S1i​==S2j​S1i​<>S2j​​

对于长度为 m 的序列 S1 和长度为 n 的序列 S2,dp[m][n] 就是序列 S1 和序列 S2 的最长公共子序列长度。

最长递增子序列 相比,最长公共子序列有以下不同点:

  • 针对的是两个序列,求它们的最长公共子序列。
  • 在最长递增子序列中,dp[i] 表示以 SiS_iSi​ 为结尾的最长递增子序列长度,子序列必须包含 SiS_iSi​ ;在最长公共子序列中,dp[i][j] 表示 S1 中前 i 个字符与 S2 中前 j 个字符的最长公共子序列长度,不一定包含 S1iS1_iS1i​ 和 S2jS2_jS2j​。
  • 在求最终解时,最长公共子序列中 dp[m][n] 就是最终解,而最长递增子序列中 dp[n] 不是最终解,因为以 SnS_nSn​ 为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。

代码:(Java)

public class LongestCommonSubsequence {public static void main(String[] args) {// TODO Auto-generated method stubString text1 = "abcde";String text2 = "ace";System.out.println(longestCommonSubsequence(text1,text2));}public static int longestCommonSubsequence(String text1, String text2) {int m = text1.length();int n = text2.length();int[][] dp = new int[m + 1][n + 1];for(int i = 1; i <= m; i++) {for(int j = 1; j <= n; j++) {if(text1.charAt(i - 1) == text2.charAt(j - 1)) {dp[i][j] = dp[i - 1][j - 1] + 1;}else {dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}return dp[m][n];}
}

运行结果:

在这里插入图片描述

复杂度分析:

  • 时间复杂度:O(mn)O(mn)O(mn),需要遍历两个字符串。
  • 空间复杂度:O(mn)O(mn)O(mn),需要m*n的二维数组。

注:仅供学习参考!

题目来源:力扣。

相关内容

热门资讯

美团外卖怎么投诉 有效方法步骤... 点外卖时,我们偶尔也会与商家或者骑手发生不愉快。有时候只是一点小事,却因为彼此不好的态度而无法释怀,...
民生易贷是正规贷款吗?民生易贷...   民生助粒贷是属于民生易贷旗下运营的一款针对个人消费开放的信贷产品这款产品自上市以来就十分稳定,审...
灵活就业养老保险交哪个档次好?...   众所周知,灵活就业人员缴纳的养老保险有着不同的档次,选择不同的档次也意味着不同的投入和回报,那么...
微信怎么查医保卡余额,如何在微...   很多小伙伴都想要查询自己的社保卡的余额信息,但是去线下查询慢效率不高。但是其实在手机微信上就可以...
社保断交有什么影响?社保断交影...   很多小伙伴都知道社保需要每个月都交,但是社保断缴会怎么样呢?如果社保断缴会导致什么严重的后果吗?...
每年交7000社保15年领多少...   退休金是很多老人之后生活的凭据,那么自己缴纳十五年的社保,每年都交7000元,那么在退休之后能领...
退休金上调2022的最新消息,...   进入8月份,2022年的退休人员的养老金上涨,那么这一部分调整了什么内容呢?这是很多小伙伴啊都存...
公积金封存满6个月当天就能取?...   公积金是很多小伙伴在工作后都会交的,那么公积金封存后满6个月可以取吗?公积金封存之后可以提现吗?...
67类“示范文本”推广使用!对... 转自:新华社客户端“机动车交通事故责任纠纷中,受害人对于具体赔偿项目通常不清楚,示范文本将常见的12...
延迟退休年龄一览表2022,延...   现在延迟退休将于2022年开始启动,预计将在2027年实施,那么很多小伙伴就存在着疑惑了,不知道...