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

news2024/11/17 1:34:27

一、最长递增子序列

题目:

给你一个整数数组 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])

代码:

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

代码:

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

代码:

public int findLength(int[] nums1, int[] nums2) {
    // 获取两个数组的长度,并将长度加1,便于创建dp数组(包含边界情况)
    int n1 = nums1.length + 1;
    int n2 = nums2.length + 1;

    // 初始化结果变量为0
    int 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]的基础上增加1
                dp[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])

代码:

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]的基础上增加1
                dp[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.coloradmin.cn/o/2049588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一款免费的开源支付网关系统,支持X宝、某信、云闪付等多种支付方式,提供收单、退款、聚合支付、对账、分账等功能(附源码)

前言 在数字化浪潮中&#xff0c;电子-商务和移动支付迅速崛起&#xff0c;支付系统成为企业运营的核心组件。然而&#xff0c;现有支付处理方案常面临成本高、集成复杂、系统耦合度高等挑战。 这些问题不仅增加了企业负担&#xff0c;也制约了业务的快速迭代和创新。市场迫切…

Tomcat的核心文件讲解

参考视频&#xff1a;对应视频 server.xml中的以下部分可修改&#xff1a; 1.connector标签里的port可以修改。--修改端口号 Tomcat默认端口号&#xff1a;8080 <Connector connectionTimeout"20000" maxParameterCount"1000"port"8080" prot…

Mac文件需要分卷压缩怎么办 Mac上怎么解压分卷压缩的文件

在处理大型文件的传输和存储的时候&#xff0c;Mac用户常面临文件大小超过限制的问题。为了有效管理这些大文件&#xff0c;分卷压缩成为一种必不可少的解决方案。Mac文件需要分卷压缩怎么办&#xff1f;Mac上怎么解压分卷压缩的文件&#xff1f;本文将向你介绍如何使用BetterZ…

STM32F103之DMA

DMA简介 DMA&#xff0c;即Direct Memory Access&#xff0c;是一种在无需CPU参与的情况下&#xff0c;将数据在存储器&#xff08;单片机的RAM&#xff09;和外设&#xff08;一般是I/O设备&#xff09;之间高效传输的硬件机制。实现这种功能的集成电路单元叫做DMA Controlle…

北京大学数学课程相关视频

今天无意中发现了一个网站&#xff1a;北京大学教学媒体资源服务平台媒体资源服务平台-北京大学&#xff0c;发现里面有一些精品的课程&#xff0c;于是将里面的数学相关可成整理出来。 北大精品课 离散数学&#xff08;2013&#xff09; 屈婉玲 课程链接&#xff1a;媒体资源…

Bugku-web-Simple_SSTl_1

开启环境 翻译一下 他说 您需要输入一个名为flag的参数。 SSTL 是一个模板注入, SECRET KEY:是flask 一个重要得配置值 需要用以下代码来加密 /?flag{{config.SECRET KEY}}(注意大小写),或直接 /?flag{{config}} 关于SSTL注入 SSTL注入&#xff0c;通常指的是‌服务器端…

Vxe UI vue vxe-table 实现表格数据分组功能,根据字段数据分组

Vxe UI vue vxe-table 实现表格数据分组功能&#xff0c;根据字段数据分组 实现数据分组功能 基于树结构功能就可以直接实现数据分组功能&#xff0c;代码如下&#xff1a; <template><div><vxe-button status"primary" click"listToGroup()&…

Self-Attention自注意力机制解读(2):图解版!

文章目录 一、前言二、流程解读1.它整体做了一件什么事2.多层Self-attention3.self-attention做了一件什么事4.具体流程 三、流程的矩阵表示三、Softmax层的解释 一、前言 上一篇文章 Self-Attention自注意力机制&#xff1a;深度学习中的动态焦点 | 手把手实例解析 看不懂你打…

Keepalived实验

keepalived在架构中的作用 LVS和HAProxy组成负载均衡 调度器LVS&#xff08;四层&#xff09;后端服务器&#xff08;多&#xff09; LVS&#xff1a;优点是速度快&#xff0c;性能要求不高&#xff0c;但是没有对后端服务器的健康检测&#xff1b; HAProxy&#xff1a;有后…

有名管道 | 信号

匿名管道由于没有名字&#xff0c;只能用于具有亲缘关系的进程间通信。 为了克服这个缺点&#xff0c;就提出了有名管道&#xff08;FIFO&#xff09;&#xff0c;也称为命名管道、FIFO文件。 有名管道 FIFO在文件系统中作为一个特殊的文件而存在并且在文件系统中可见&#…

8个最佳iMacros替代方案(2024)

iMacros作为一款经典的网页自动化工具&#xff0c;多年来帮助无数用户自动化了繁琐的网页任务。然而&#xff0c;随着技术的进步&#xff0c;越来越多功能更强大、界面更友好的替代方案涌现&#xff0c;为用户提供了更多选择。如果你正在寻找2024年最好的iMacros替代工具&#…

中国智能物流系统集成玩家图谱:很全

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 上海欣巴自动化科技股份有限公司 总部&#xff1a;上海服务行业&#xff1a;快递、电商、服装、零售、医药、食品饮料等解决方案&#xff1a;自动化分拣输送系统&#xff1b;控制软件…

linux下tomcat nio 底层源码调用系统函数处理流程

linux tomcat使用nio处理请求 调用jvm native C 底层调用系统函数源码原理 ##Acceptor接受socket socket endpoint.serverSocketAccept(); ##NioEndpoint serverSock.accept() ##ServerSocketChannelImpl n accept(this.fd, newfd, isaa); ##ServerSocketChannelImpl a…

Linux的安装和使用

Linux 第一节 Linux 优势 1. 开源 为什么这么多的的设备都选择使用 Linux&#xff1f;因为它是开源软件&#xff08;open source software&#xff09;&#xff0c;具有不同的含义。使用一个安全的操作系统工作变得必不可少的事&#xff0c;而 Linux 恰好满足了这个需求。因…

Golang | Leetcode Golang题解之第344题反转字符串

题目&#xff1a; 题解&#xff1a; func reverseString(s []byte) {for left, right : 0, len(s)-1; left < right; left {s[left], s[right] s[right], s[left]right--} }

vue3ts+element-plus实现点击el-select下拉选择内容填充和编辑内容

需求在填写报表时&#xff0c;既可以选择下拉选项&#xff0c;还可以编辑选的内容&#xff0c; 找了elementUi没有现成的就自己组装一个 效果&#xff1a; 贴代码&#xff1a; 在components下新建文件夹TextareaSelect&#xff0c;再新建index.vue和interface.ts &#xff08;…

AIGC创新应用技术实践:成都技术生态沙龙全回顾

AIGC创新应用技术实践&#xff1a;成都技术生态沙龙全回顾 2024年8月17日下午&#xff0c;我有幸作为CSDN校园主理人参加了在成都举办的AIGC创新应用技术实践沙龙活动。 此行也见到了许许多多的行业大佬&#xff0c;得到的收获非常之多&#xff0c;赶了1300公里的路&#xff0…

getActivePinia was called with no active Pinia

如果你是从vuex转向使用pinia&#xff0c;那么你可能遇到这个问题getActivePinia was called with no active Pinia. Did you forget to install pinia?。明明已经安装了pinia&#xff0c;为什么会有这个提示呢&#xff1f; 原因是你可能在setup的组件之外使用了useStore 根本…

JavaScript初级——运算符

一、算数运算符 1、运算符也叫操作符。通过运算符可以对一个或多个值进行运算&#xff0c;并获取运算结果。 比如&#xff1a;typeof 就是运算符&#xff0c;可以获得一个值的类型&#xff0c;他会将该值的类型以字符串的形式返回 &#xff08;number、string、boolean、undefi…

三防平板:现代生产效率与安全的革新者

三防加固工业平板电脑以其独特的防水、防尘、防摔性能&#xff0c;成为复杂生产环境下可靠的工作伙伴。无论是高温、高湿的恶劣环境&#xff0c;还是充满粉尘与振动的车间&#xff0c;三防平板电脑均能保持稳定运行&#xff0c;显著降低硬件故障率&#xff0c;确保生产线的平稳…