算法日记day 41(动归之最长序列问题)

embedded/2024/9/24 14:56:50/

一、最长递增子序列

题目:

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

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

 

思路:

首先明确dp数组的含义,本题中dp数组含义是在结尾是nums[i]的最长递增子序列的长度为dp[i],由于dp数组由nums数组相照应,因此对dp数组中的所有元素均初始化为1,启用一个判断条件,若后者元素值大于前者,则结果值加一,因此dp数组的递归关系式为

                                              dp[i] = max(dp[j]+1,dp[i])

代码:

java">public int lengthOfLIS(int[] nums) {int n = nums.length; // 获取输入数组的长度int[] dp = new int[n]; // 创建一个数组 dp,用于记录以每个元素为结尾的最长递增子序列的长度// 初始化 dp 数组,每个位置的初始值设为 1// 因为每个元素至少可以组成一个长度为 1 的递增子序列(它自己)for (int i = 0; i < n; i++) {dp[i] = 1;}int result = 1; // 初始化 result,用于记录全局的最长递增子序列的长度// 遍历每个元素,确定以每个元素为结尾的最长递增子序列的长度for (int i = 0; i < n; i++) {for (int j = 0; j < i; j++) {// 如果 nums[j] 小于 nums[i],说明 nums[i] 可以接在 nums[j] 后面形成递增子序列if (nums[j] < nums[i]) {// 更新 dp[i] 为以 nums[i] 结尾的最长递增子序列的长度dp[i] = Math.max(dp[j] + 1, dp[i]);}}// 更新 result 为当前最大递增子序列的长度result = result > dp[i] ? result : dp[i];}// 返回全局最长递增子序列的长度return result;
}
  • n 是输入数组 nums 的长度。
  • dp 数组用于存储以 nums[i] 为结尾的最长递增子序列的长度。初始化 dp[i] 为 1,表示每个元素自身是一个长度为 1 的递增子序列。
  • 外层循环 i 遍历数组的每一个元素。
  • 内层循环 j 遍历 i 前面的所有元素,检查是否存在比 nums[i] 小的元素。
  • 如果 nums[j] < nums[i],则说明 nums[i] 可以接在 nums[j] 后面形成一个递增子序列,因此更新 dp[i] 为 dp[j] + 1 和 dp[i] 的较大值。
  • 更新 result 为当前的 dp[i] 和 result 的较大值,记录全局的最大递增子序列长度。
  • 最终,result 存储了数组中最长递增子序列的长度,返回这个值。

二、最长连续递增子序列 

题目:

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 l 和 rl < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

示例 1:

输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。 

示例 2:

输入:nums = [2,2,2,2,2]
输出:1
解释:最长连续递增序列是 [2], 长度为1。

思路:

dp数组的含义是nums数组中第 i 个元素的最长连续连续子序列的产地古为dp[i],与最长连续子序列不同的是,本题子序列中的元素必须前后连续,因此需要比较的是i+1与i元素的大小,dp数组初始化仍为1,递归关系为

                            

                                            dp[i+1] = dp[i]+1

代码:

java">public int findLengthOfLCIS(int[] nums) {int n = nums.length; // 获取输入数组的长度int[] dp = new int[n]; // 创建一个数组 dp,用于记录以每个元素为结尾的最长连续递增子序列的长度// 初始化 dp 数组,每个位置的初始值设为 1// 因为每个元素至少可以组成一个长度为 1 的递增子序列(它自己)for (int i = 0; i < dp.length; i++) {dp[i] = 1;}int result = 1; // 初始化 result,用于记录全局的最长连续递增子序列的长度// 遍历数组中的每一对相邻元素for (int i = 0; i < n - 1; i++) {// 如果当前元素小于下一个元素,说明可以继续形成递增子序列if (nums[i + 1] > nums[i]) {dp[i + 1] = dp[i] + 1; // 更新 dp[i + 1],表示以 nums[i + 1] 为结尾的递增子序列长度}// 更新 result 为当前的 dp[i + 1] 和 result 的较大值result = result > dp[i + 1] ? result : dp[i + 1];}// 返回全局最长连续递增子序列的长度return result;
}
  • n 是输入数组 nums 的长度。
  • dp 数组用于存储以每个元素为结尾的最长连续递增子序列的长度。初始化 dp[i] 为 1,表示每个元素自身是一个长度为 1 的递增子序列。
  • 遍历数组中的每一对相邻元素,通过 i 和 i + 1 访问。
  • 如果 nums[i + 1] > nums[i],说明 nums[i + 1] 可以继续延续前面的递增子序列,因此更新 dp[i + 1] 为 dp[i] + 1
  • 更新 result 为当前的 dp[i + 1] 和 result 的较大值,以保持全局的最大连续递增子序列长度。
  • 最终,result 变量保存了数组中最长的连续递增子序列的长度,返回这个值。

三、最长重复子数组 

题目:

给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 

示例 1:

输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。

示例 2:

输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5

思路:

有关两个数组中比较最长的公共子数组,定义dp数组以i-1为结尾的在nums1数组和以j-1为结尾nums2数组中的最长公共子数组为dp[i][j],不难推出dp数组的递推公式

                                          dp[i][j] = dp[i-1][j-1]+1

代码:

java">public int findLength(int[] nums1, int[] nums2) {// 获取两个数组的长度,并将长度加1,便于创建dp数组(包含边界情况)int n1 = nums1.length + 1;int n2 = nums2.length + 1;// 初始化结果变量为0int result = 0;// 创建dp二维数组,dp[i][j]表示以nums1[i-1]和nums2[j-1]结尾的最长公共子数组的长度int[][] dp = new int[n1][n2];// 遍历dp数组填充数据for (int i = 1; i < n1; i++) {for (int j = 1; j < n2; j++) {// 如果nums1的第i-1个元素等于nums2的第j-1个元素if (nums1[i - 1] == nums2[j - 1]) {// 更新dp[i][j],表示在dp[i-1][j-1]的基础上增加1dp[i][j] = dp[i - 1][j - 1] + 1;}// 更新结果为当前dp[i][j]和已有结果的最大值if (dp[i][j] > result) {result = dp[i][j];}}}// 返回最长公共子数组的长度return result;
}
  • n1 和 n2 是 nums1 和 nums2 长度加 1,用于构建 dp 数组(用于存储最长公共子数组的长度)。
  • result 用于保存最终的最长公共子数组的长度。
  • dp 数组的 dp[i][j] 存储 nums1[0..i-1] 和 nums2[0..j-1] 中的最长公共子数组的长度。
  • 通过双重循环遍历 dp 数组。i 和 j 分别代表 nums1 和 nums2 中的索引。
  • 当 nums1[i - 1] 等于 nums2[j - 1] 时,dp[i][j] 表示以 nums1[i - 1] 和 nums2[j - 1] 为结尾的最长公共子数组的长度。
  • 如果 dp[i][j] 大于当前 result,则更新 result
  • 返回最长公共子数组的长度。

四、最长公共子序列 

题目:

给定两个字符串 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 。

思路:

首先明确dp数组的含义,本题中dp数组为对于长度为[0,i-1]的text1数组和长度为[0,j-1]的text2数组,他们的最长公共子序列为dp[i][j],对于对应元素值相同的情况,dp数组的递推式为

                                                      dp[i][j] = dp[i-1][j-1] + 1

对于相对应元素不相同的情况

例如text1="abc",text2="ace"此时处理起来应该取dp[i][j-1]的长度,即为text1中跳过第二个元素取第三个,或者text2中取前两个元素舍弃第三个

同理如果是text1="ace",text2="abc",此时处理起来应该取dp[i-1][j]的长度,即为text1中取前两个元素,或者text2舍弃第三个跳过第二个元素取第三个,两者之前取最大值,因此递推式为

                                               dp[i][j] = max(dp[i-1][j],dp[i][j-1])

代码:

java">public int longestCommonSubsequence(String text1, String text2) {// 获取两个字符串的长度,并将长度加1,便于创建dp数组(包含边界情况)int n1 = text1.length() + 1;int n2 = text2.length() + 1;// 将字符串转换为字符数组char[] c1 = text1.toCharArray();char[] c2 = text2.toCharArray();// 创建dp二维数组,dp[i][j]表示text1前i个字符和text2前j个字符的最长公共子序列长度int[][] dp = new int[n1][n2];// 遍历dp数组填充数据for (int i = 1; i < n1; i++) {for (int j = 1; j < n2; j++) {// 如果text1的第i-1个字符等于text2的第j-1个字符if (c1[i - 1] == c2[j - 1]) {// 更新dp[i][j],表示在dp[i-1][j-1]的基础上增加1dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 否则dp[i][j]取dp[i-1][j]和dp[i][j-1]的最大值dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}// 返回最长公共子序列的长度return dp[text1.length()][text2.length()];
}
  • n1 和 n2 是 text1 和 text2 的长度加 1,用于创建 dp 数组,以包含边界条件。
  • c1 和 c2 是将 text1 和 text2 转换为字符数组。
  • dp 数组的 dp[i][j] 存储 text1[0..i-1] 和 text2[0..j-1] 的最长公共子序列的长度。
  • 遍历 dp 数组。i 和 j 分别表示 text1 和 text2 中的索引。
  • 当 c1[i - 1] 等于 c2[j - 1] 时,dp[i][j] 表示在 dp[i-1][j-1] 的基础上增加 1。
  • 否则,dp[i][j] 取 dp[i-1][j] 和 dp[i][j-1] 的最大值,表示不匹配时最长公共子序列的长度。
  • 返回 dp 数组中最后一个元素,即 text1 和 text2 的最长公共子序列的长度。

今天的学习就到这里 


http://www.ppmy.cn/embedded/97164.html

相关文章

Linux驱动入门实验班——LED驱动(附百问网视频链接)

目录 一、确定引脚编号 二、编写思路 2.1驱动层 2.2应用层 三、源码 四、实现 课程链接 一、确定引脚编号 首先&#xff0c;可以在开发板上执行如下命令查看已经在使用的GPIO状态&#xff1a; cat /sys/kernel/debug/gpio 可以看到每个gpio都有对应的编号&#xff0c;…

计算机网络中用于远程访问和文件传输的不同方式

SSH (Secure Shell) 定义&#xff1a;SSH是一种网络协议&#xff0c;用于安全的数据通信、命令执行和远程登录。SSH使用公钥加密技术来建立安全的连接。客户端和服务器之间通过加密通道交换数据&#xff0c;保证数据的完整性和机密性。适用场景&#xff1a;服务器管理、远程文…

Selenium + Python 自动化测试14(发送报告)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了使用HTMLTestRunner 生成HTML报告的方法。 本篇文章我们接着讲生成HTML报告是否可以自动邮件发送出去&#xff0c;提高我们测试报告的及时性&#xff0c;方便…

如何将TRIZ的“最终理想解”应用到机器人电机控制设计中?

TRIZ理论&#xff0c;作为一套系统的创新方法论&#xff0c;旨在帮助设计师和工程师突破思维惯性&#xff0c;解决复杂的技术难题。其核心思想之一便是“最终理想解”&#xff0c;它如同一盏明灯&#xff0c;指引着我们在技术创新的道路上不断前行。最终理想解追求的是产品或技…

本地ComfyUI安装全记录

资料 先看我写的stable diffusion全记录 ComfyUI 完全入门&#xff1a;安装部署 ComfyUI 完全入门&#xff1a;图生视频 ComfyUI【强烈推荐】 秋葉aaaki comfy UI整合包 可以使用stable diffusion的大模型&#xff0c;通过修改文件重新指向 修改路径即可 下载秋叶大佬的…

Unity动画模块 之 3D模型导入基础设置Model页签

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 创建模型&#xff1a;在 Unity 外部创建模型 - Unity 手册 导入模型&#xff1a;将模型导入 Unity - Unity 手册 1.…

Kafka中查找某个topic是否包含某个字符串

要在Kafka中查找某个topic是否包含某个字符串&#xff0c;您可以通过以下几个步骤&#xff1a; 使用Kafka的命令行工具kafka-console-consumer来消费topic的消息。这个工具可以让您从某个topic读取消息并将其输出到控制台。例如&#xff0c;要从名为my_topic的topic读取消息&a…

18.1 使用python进行网络请求与数据解析

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。 ⭐…