代码随想录训练营day53| 1143.最长公共子序列 1035.不相交的线 53. 最大子序和...

简介: 代码随想录训练营day53| 1143.最长公共子序列 1035.不相交的线 53. 最大子序和...

前言

代码随想录算法训练营day53


一、Leetcode 1143.最长公共子序列

1.题目

给定两个字符串 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. 1 <= text1.length, text2.length <= 1000
2. text1 和 text2 仅由小写英文字符组成。

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/longest-common-subsequence

2.解题思路

方法一:动态规划

最长公共子序列问题是典型的二维动态规划问题。

假设字符串 text1text1 和 text2text2 的长度分别为 mm 和 nn,创建 m+1m+1 行 n+1n+1 列的二维数组 dpdp,其中 dp[i][j]dp[i][j] 表示 text1[0:i]text1[0:i] 和 text2[0:j]text2[0:j] 的最长公共子序列的长度。

上述表示中,text1[0:i]text1[0:i] 表示 text1text1 的长度为 ii 的前缀,text2[0:j]text2[0:j] 表示 text2text2 的长度为 jj 的前缀。

考虑动态规划的边界情况:

1. 当 i=0i=0 时,text1[0:i]text1[0:i] 为空,空字符串和任何字符串的最长公共子序列的长度都是 00,因此对任意 0≤j≤n0≤j≤n,有 dp[0][j]=0dp[0][j]=0;
2. 
3. 当 j=0j=0 时,text2[0:j]text2[0:j] 为空,同理可得,对任意 0≤i≤m0≤i≤m,有 dp[i][0]=0dp[i][0]=0。

因此动态规划的边界情况是:当 i=0i=0 或 j=0j=0 时,dp[i][j]=0dp[i][j]=0。

当 i>0i>0 且 j>0j>0 时,考虑 dp[i][j]dp[i][j] 的计算:

1. 当 text1[i−1]=text2[j−1]text1[i−1]=text2[j−1] 时,将这两个相同的字符称为公共字符,考虑 text1[0:i−1]text1[0:i−1] 和 text2[0:j−1]text2[0:j−1] 的最长公共子序列,再增加一个字符(即公共字符)即可得到 text1[0:i]text1[0:i] 和 text2[0:j]text2[0:j] 的最长公共子序列,因此 dp[i][j]=dp[i−1][j−1]+1dp[i][j]=dp[i−1][j−1]+1。
2. 
3. 当 text1[i−1]≠text2[j−1]text1[i−1]=text2[j−1] 时,考虑以下两项:
4. 
5.     text1[0:i−1]text1[0:i−1] 和 text2[0:j]text2[0:j] 的最长公共子序列;
6. 
7.     text1[0:i]text1[0:i] 和 text2[0:j−1]text2[0:j−1] 的最长公共子序列。
8. 
9. 要得到 text1[0:i]text1[0:i] 和 text2[0:j]text2[0:j] 的最长公共子序列,应取两项中的长度较大的一项,因此 dp[i][j]=max⁡(dp[i−1][j],dp[i][j−1])dp[i][j]=max(dp[i−1][j],dp[i][j−1])。

由此可以得到如下状态转移方程:

dp[i][j]={dp[i−1][j−1]+1,text1[i−1]=text2[j−1]max⁡(dp[i−1][j],dp[i][j−1]),text1[i−1]≠text2[j−1]dp[i][j]={dp[i−1][j−1]+1,max(dp[i−1][j],dp[i][j−1]),text1[i−1]=text2[j−1]text1[i−1]=text2[j−1]

最终计算得到 dp[m][n]dp[m][n] 即为 text1text1 和 text2text2 的最长公共子序列的长度。

3.代码实现

```java class Solution { public int longestCommonSubsequence(String text1, String text2) { int m = text1.length(), n = text2.length(); int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { char c1 = text1.charAt(i - 1); for (int j = 1; j <= n; j++) { char c2 = text2.charAt(j - 1); if (c1 == c2) { 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]; } }
```

二、Leetcode 1035.不相交的线

1.题目

在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。

现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足满足:

1. nums1[i] == nums2[j]
2. 且绘制的直线不与任何其他连线(非水平线)相交。

请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。

以这种方法绘制线条,并返回可以绘制的最大连线数。

示例 1:

输入:nums1 = [1,4,2], nums2 = [1,2,4] 输出:2 解释:可以画出两条不交叉的线,如上图所示。 但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。

示例 2:

输入:nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2] 输出:3

示例 3:

输入:nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1] 输出:2

提示:

1. 1 <= nums1.length, nums2.length <= 500
2. 1 <= nums1[i], nums2[j] <= 2000

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/uncrossed-lines

2.解题思路

方法一:动态规划

给定两个数组 nums1nums1 和 nums2nums2,当 nums1[i]=nums2[j]nums1[i]=nums2[j] 时,可以用一条直线连接 nums1[i]nums1[i] 和 nums2[j]nums2[j]。假设一共绘制了 kk 条互不相交的直线,其中第 xx 条直线连接 nums1[ix]nums1[ix] 和 nums2[jx]nums2[jx],则对于任意 1≤x≤k1≤x≤k 都有 nums1[ix]=nums2[jx]nums1[ix]=nums2[jx],其中 i1

上述 kk 条互不相交的直线分别连接了数组 nums1nums1 和 nums2nums2 的 kk 对相等的元素,而且这 kk 对相等的元素在两个数组中的相对顺序是一致的,因此,这 kk 对相等的元素组成的序列即为数组 nums1nums1 和 nums2nums2 的公共子序列。要计算可以绘制的最大连线数,即为计算数组 nums1nums1 和 nums2nums2 的最长公共子序列的长度。最长公共子序列问题是典型的二维动态规划问题。

假设数组 nums1nums1 和 nums2nums2 的长度分别为 mm 和 nn,创建 m+1m+1 行 n+1n+1 列的二维数组 dpdp,其中 dp[i][j]dp[i][j] 表示 nums1[0:i]nums1[0:i] 和 nums2[0:j]nums2[0:j] 的最长公共子序列的长度。

上述表示中,nums1[0:i]nums1[0:i] 表示数组 nums1nums1 的长度为 ii 的前缀,nums2[0:j]nums2[0:j] 表示数组 nums2nums2 的长度为 jj 的前缀。

考虑动态规划的边界情况:

1. 当 i=0i=0 时,nums1[0:i]nums1[0:i] 为空,空数组和任何数组的最长公共子序列的长度都是 00,因此对任意 0≤j≤n0≤j≤n,有 dp[0][j]=0dp[0][j]=0;
2. 
3. 当 j=0j=0 时,nums2[0:j]nums2[0:j] 为空,同理可得,对任意 0≤i≤m0≤i≤m,有 dp[i][0]=0dp[i][0]=0。

因此动态规划的边界情况是:当 i=0i=0 或 j=0j=0 时,dp[i][j]=0dp[i][j]=0。

当 i>0i>0 且 j>0j>0 时,考虑 dp[i][j]dp[i][j] 的计算:

1. 当 nums1[i−1]=nums2[j−1]nums1[i−1]=nums2[j−1] 时,将这两个相同的元素称为公共元素,考虑 nums1[0:i−1]nums1[0:i−1] 和 nums2[0:j−1]nums2[0:j−1] 的最长公共子序列,再增加一个元素(即公共元素)即可得到 nums1[0:i]nums1[0:i] 和 nums2[0:j]nums2[0:j] 的最长公共子序列,因此 dp[i][j]=dp[i−1][j−1]+1dp[i][j]=dp[i−1][j−1]+1。
2. 
3. 当 nums1[i−1]≠nums2[j−1]nums1[i−1]=nums2[j−1] 时,考虑以下两项:
4. 
5.     nums1[0:i−1]nums1[0:i−1] 和 nums2[0:j]nums2[0:j] 的最长公共子序列;
6. 
7.     nums1[0:i]nums1[0:i] 和 nums2[0:j−1]nums2[0:j−1] 的最长公共子序列。
8. 
9. 要得到 nums1[0:i]nums1[0:i] 和 nums2[0:j]nums2[0:j] 的最长公共子序列,应取两项中的长度较大的一项,因此 dp[i][j]=max⁡(dp[i−1][j],dp[i][j−1])dp[i][j]=max(dp[i−1][j],dp[i][j−1])。

由此可以得到如下状态转移方程:

dp[i][j]={dp[i−1][j−1]+1,nums1[i−1]=nums2[j−1]max⁡(dp[i−1][j],dp[i][j−1]),nums1[i−1]≠nums2[j−1]dp[i][j]={dp[i−1][j−1]+1,max(dp[i−1][j],dp[i][j−1]),nums1[i−1]=nums2[j−1]nums1[i−1]=nums2[j−1]

最终计算得到 dp[m][n]dp[m][n] 即为数组 nums1nums1 和 nums2nums2 的最长公共子序列的长度,即可以绘制的最大连线数。

fig1

3.代码实现

```java class Solution { public int maxUncrossedLines(int[] nums1, int[] nums2) { int m = nums1.length, n = nums2.length; int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { int num1 = nums1[i - 1]; for (int j = 1; j <= n; j++) { int num2 = nums2[j - 1]; if (num1 == num2) { 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]; } }
```

三、Leetcode 53. 最大子序和

1.题目

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1] 输出:1

示例 3:

输入:nums = [5,4,-1,7,8] 输出:23

提示:

1. 1 <= nums.length <= 105
2. -104 <= nums[i] <= 104

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/maximum-subarray

2.解题思路

方法一:动态规划

思路和算法

假设 numsnums 数组的长度是 nn,下标从 00 到 n−1n−1。

我们用 f(i)f(i) 代表以第 ii 个数结尾的「连续子数组的最大和」,那么很显然我们要求的答案就是:

max⁡0≤i≤n−1{f(i)}0≤i≤n−1max{f(i)}

因此我们只需要求出每个位置的 f(i)f(i),然后返回 ff 数组中的最大值即可。那么我们如何求 f(i)f(i) 呢?我们可以考虑 nums[i]nums[i] 单独成为一段还是加入 f(i−1)f(i−1) 对应的那一段,这取决于 nums[i]nums[i] 和 f(i−1)+nums[i]f(i−1)+nums[i] 的大小,我们希望获得一个比较大的,于是可以写出这样的动态规划转移方程:

f(i)=max⁡{f(i−1)+nums[i],nums[i]}f(i)=max{f(i−1)+nums[i],nums[i]}

不难给出一个时间复杂度 O(n)O(n)、空间复杂度 O(n)O(n) 的实现,即用一个 ff 数组来保存 f(i)f(i) 的值,用一个循环求出所有 f(i)f(i)。考虑到 f(i)f(i) 只和 f(i−1)f(i−1) 相关,于是我们可以只用一个变量 prepre 来维护对于当前 f(i)f(i) 的 f(i−1)f(i−1) 的值是多少,从而让空间复杂度降低到 O(1)O(1),这有点类似「滚动数组」的思想。

3.代码实现

```java class Solution { public int maxSubArray(int[] nums) { int pre = 0, maxAns = nums[0]; for (int x : nums) { pre = Math.max(pre + x, x); maxAns = Math.max(maxAns, pre); } return maxAns; } }


相关文章
|
机器学习/深度学习 人工智能 算法
黑盒模型事后归因解析:SHAP 方法
近年来人工智能的浪潮越来越汹涌,以神经网络、集成模型为代表的机器学习模型在数据挖掘领域中发挥着不可替代的作用。在追求模型高精度的道路上,工业界和学术界也十分关注模型的可解释性,期待从复杂模型中得到更直观的理解。
|
机器学习/深度学习 资源调度 JavaScript
机器学习概念漂移检测方法(Aporia)
目前,有多种技术可用于机器学习检测概念漂移的方法。熟悉这些检测方法是为每个漂移和模型使用正确度量的关键。 在本文章中,回顾了四种类型的检测方法:统计、统计过程控制、基于时间窗口和上下文方法。
|
资源调度 运维 监控
SLS机器学习介绍(03):时序异常检测建模
虽然计算机软硬件的快速发展已经极大提高了应用程序的可靠性,但是在大型集群中仍然存在大量的软件错误和硬件故障。系统要求7x24小时不间断运行,因此,对这些系统进行持续监控至关重要。这就要求我们就被从系统中持续采集系统运行日志,业务运行日志的能力,并能快速的分析和监控当前状态曲线的异常,一旦发现异常,能第一时间将信息送到相关人员手中。
24386 0
SLS机器学习介绍(03):时序异常检测建模
|
2天前
|
数据采集 人工智能 安全
|
11天前
|
云安全 监控 安全
|
3天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
1017 151
|
3天前
|
编解码 人工智能 机器人
通义万相2.6,模型使用指南
智能分镜 | 多镜头叙事 | 支持15秒视频生成 | 高品质声音生成 | 多人稳定对话
|
16天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1711 9
|
8天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
652 152