第五十三天| 1143.最长公共子序列、1035.不相交的线、53. 最大子序和

2024-03-11 02:52

本文主要是介绍第五十三天| 1143.最长公共子序列、1035.不相交的线、53. 最大子序和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Leetcode 1143.最长公共子序列

题目链接:1143 最长公共子序列

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

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

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

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

思考:动态规划。

  • 确定dp数组(dp table)以及下标的含义

dp[i][j]:字符串text1的处理区间[0, i - 1]与字符串text2的处理区间[0, j - 1]中,存在的最长公共子序列的长度。

至于为什么要定义长度为[0, i - 1]的字符串text1,而不是定义为长度为[0, i]的字符串text1。

这主要是为了简化初始化操作,具体理由在 Leetcode 718. 最长重复子数组 中有讲解。

  • 确定递推公式

遍历过程就两种情况: text1[i - 1] 与 text2[j - 1]相同 以及 text1[i - 1] 与 text2[j - 1]不相同。

如果text1[i - 1] 与 text2[j - 1]相同,即找到一个公共元素,则在 text1[0, i - 2]与text2[0, j - 2]的最长公共子序列的末尾再加上此次找到的公共元素(即两字符串均缩小处理区间的结果加一)。因此dp[i][j] = dp[i - 1][j - 1] + 1;

如果text1[i - 1] 与 text2[j - 1]不相同,那就比较text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列(即任选一字符串缩小处理区间的结果),取最大的,则dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

  • dp数组如何初始化

test1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;同理dp[0][j]也是0。

其他下标都是随着递推公式逐步覆盖,初始为多少都可以,所以可以统一初始为0。

  • 确定遍历顺序

从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:

在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历矩阵。

  • 举例推导dp数组

举例:text1 = "abcde", text2 = "ace" ,dp状态如图:

代码:

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {//dp[i][j]:字符串text1的处理区间[0, i - 1]与字符串text2的处理区间[0, j - 1]中,存在的最长公共子序列的长度vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));     for (int i = 1; i <= text1.size(); i++) {           //遍历text1字符串for (int j = 1; j <= text2.size(); j++) {       //遍历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]);     }}return dp[text1.size()][text2.size()];}
};

Leetcode 1035.不相交的线

题目链接:1035 不相交的线

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

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

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

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

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

思考:动态规划。本题如果从怎么判断连线相交的角度思考会卡壳,如果将不相交理解为前后连线元素的相对顺序和数组的相对顺序一致,可以发现本题和上题一模一样。

直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。

因此本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度。

代码:

class Solution {
public:int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {//dp[i][j]: 数组nums1的处理区间[0, i - 1]与数组nums2的处理区间[0, j - 1]中,存在的最大连线数vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));for (int i = 1; i <= nums1.size(); i++) {           //遍历数组nums1for (int j = 1; j <= nums2.size(); j++){        //遍历数组nums2if (nums1[i - 1] == nums2[j - 1])//当前处理两元素可连线 则 取两数组均缩小处理区间的连线数加一dp[i][j] = dp[i - 1][j - 1] + 1;        else//当前处理两元素不可连线 则 取任选一数组缩小处理区间的连线数,两连线数中的较大值                                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);    }}return dp[nums1.size()][nums2.size()];}
};

Leetcode 53. 最大子序和

题目链接:53 最大子序和

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

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

思考:此题的贪心法解法:53. 最大子序和。下面为动态规划解法。

  • 确定dp数组(dp table)以及下标的含义

dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和。

  • 确定递推公式

从dp[i]的定义,可以看出dp[i]只有两个方向可以推出:

  • dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
  • nums[i],即:从头开始计算当前连续子序列和

并且要取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);

  • dp数组如何初始化

从递推公式可以看出来dp[i]是依赖于dp[i - 1]的状态,dp[0]就是递推公式的基础。

根据dp[i]的定义,明显dp[0]应为nums[0]即dp[0] = nums[0]。

  • 确定遍历顺序

递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。

  • 举例推导dp数组

举例:nums = [-2,1,-3,4,-1,2,1,-5,4],对应的dp状态如下:

要找最大的连续子序列和,就应该比较每一个i为终点的连续最大子序列和。取其中最大值。

代码:

class Solution {
public:int maxSubArray(vector<int>& nums) {vector<int> dp(nums.size());        //dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和dp[0] = nums[0];int result = dp[0];       //记录最大和for (int i = 1; i < nums.size(); i++) {dp[i] = max(dp[i - 1] + nums[i], nums[i]);        //递推公式if (dp[i] > result) result = dp[i];}return result;}
};

自我总结:

        最长公共子序列和还没理解清晰。

这篇关于第五十三天| 1143.最长公共子序列、1035.不相交的线、53. 最大子序和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/796378

相关文章

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

关于最长递增子序列问题概述

《关于最长递增子序列问题概述》本文详细介绍了最长递增子序列问题的定义及两种优化解法:贪心+二分查找和动态规划+状态压缩,贪心+二分查找时间复杂度为O(nlogn),通过维护一个有序的“尾巴”数组来高效... 一、最长递增子序列问题概述1. 问题定义给定一个整数序列,例如 nums = [10, 9, 2

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

poj3261(可重复k次的最长子串)

题意:可重复k次的最长子串 解题思路:求所有区间[x,x+k-1]中的最小值的最大值。求sa时间复杂度Nlog(N),求最值时间复杂度N*N,但实际复杂度很低。题目数据也比较水,不然估计过不了。 代码入下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring

poj1330(LCA最近公共祖先)

题意:求最近公共祖先 思路:之前学习了树链剖分,然后我就用树链剖分的一小部分知识就可以解这个题目了,记录每个结点的fa和depth。然后查找时,每次将depth大的结点往上走直到x = y。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring>

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

uva 10131 最长子序列

题意: 给大象的体重和智商,求体重按从大到小,智商从高到低的最长子序列,并输出路径。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vect

poj 3723 kruscal,反边取最大生成树。

题意: 需要征募女兵N人,男兵M人。 每征募一个人需要花费10000美元,但是如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱。 给出若干的男女之间的1~9999之间的亲密关系度,征募某个人的费用是10000 - (已经征募的人中和自己的亲密度的最大值)。 要求通过适当的招募顺序使得征募所有人的费用最小。 解析: 先设想无向图,在征募某个人a时,如果使用了a和b之间的关系