代码随想录刷题day53|最长公共子序列不相交的线最大子序和

本文主要是介绍代码随想录刷题day53|最长公共子序列不相交的线最大子序和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • day53学习内容
  • 一、最长公共子序列
    • 1.1、动态规划五部曲
      • 1.1.1、 确定dp数组(dp table)以及下标的含义
      • 1.1.2、确定递推公式
      • 1.1.3、 dp数组如何初始化
      • 1.1.4、确定遍历顺序
      • 1.1.5、输出结果
    • 1.2、代码
  • 二、不相交的线
    • 2.1、动态规划五部曲
      • 2.1.1、 确定dp数组(dp table)以及下标的含义
      • 2.1.2、确定递推公式
      • 2.1.3、 dp数组如何初始化
      • 2.1.4、确定遍历顺序
      • 2.1.5、输出结果
    • 2.2、代码
  • 三、最大子序和
    • 3.1、动态规划五部曲
      • 3.1.1、 确定dp数组(dp table)以及下标的含义
      • 3.1.2、确定递推公式
      • 3.1.3、 dp数组如何初始化
      • 3.1.4、确定遍历顺序
      • 3.1.5、输出结果
    • 3.2、代码
  • 总结
    • 1.感想
    • 2.思维导图


day53学习内容

day53主要内容

  • 最长公共子序列
  • 不相交的线
  • 最大子序和

声明
本文思路和文字,引用自《代码随想录》


一、最长公共子序列

1143.原题链接

1.1、动态规划五部曲

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

  • dp[i][j] 表示字符串 text1 的前 i 个字符和字符串 text2 的前 j 个字符的最长公共子序列的长度。

1.1.2、确定递推公式

基本思路
我们可以根据两个字符串中当前字符是否相等,采取不同的策略来更新 dp 表。
与最长公共子数组(或子串)不同,子序列不要求元素在原字符串中是连续的,只要求它们保持相对顺序即可。

推导状态转移方程

  1. 字符匹配的情况
    text1[i-1] == text2[j-1] 时,这意味着这两个字符可以成为目前为止考虑的字符串的公共子序列的一部分。因此,这两个字符将增加公共子序列的长度,即
dp[i][j]=dp[i−1][j−1]+1

这个方程表明,text1 的前 i 个字符和 text2 的前 j 个字符的最长公共子序列可以通过在它们的前 i-1 个字符和前 j-1 个字符的最长公共子序列的基础上添加这两个匹配的字符来得到。

  1. 字符不匹配的情况
    text1[i-1] != text2[j-1] 时,最长公共子序列不能同时包括这两个字符。因此,有以下两种可能性:
    • 忽略 text1 的当前字符 i-1,只考虑 text1 的前 i-1 个字符和 text2 的前 j 个字符。
    • 忽略 text2 的当前字符 j-1,只考虑 text1 的前 i 个字符和 text2 的前 j-1 个字符。
      这两种情况下的最长公共子序列的长度将是:
dp[i][j]=max(dp[i−1][j],dp[i][j−1])

这个方程表明,当前的 dp[i][j] 应取前面两种情况中更长的子序列长度。

1.1.3、 dp数组如何初始化

  • dp[0][x]dp[x][0] 应该初始化为 0,因为一个长度为 0 的字符串与任何字符串的最长公共子序列长度都是 0。
  • 或者这句话看不懂,就画个图。。。看一下推导的方向就明白了
    在这里插入图片描述
    图引用自卡尔的视频。

https://www.bilibili.com/video/BV1ye4y1L7CQ/?spm_id_from=pageDriver&vd_source=266f115062b99cd2d8e5185add0b8cc9

1.1.4、确定遍历顺序

从小到大遍历

1.1.5、输出结果

  • return dp[text1.length()][text2.length()]; 最后,dp 数组的最后一个元素(即 dp[text1.length()][text2.length()])包含了整个 text1text2 的最长公共子序列的长度。

1.2、代码

class Solution {public int longestCommonSubsequence(String text1, String text2) {// 创建二维数组dp,大小为text1长度+1和text2长度+1int[][] dp = new int[text1.length() + 1][text2.length() + 1];// 遍历text1的每一个字符for (int i = 1; i <= text1.length(); i++) {char char1 = text1.charAt(i - 1); // 获取text1的第i-1个字符// 遍历text2的每一个字符for (int j = 1; j <= text2.length(); j++) {char char2 = text2.charAt(j - 1); // 获取text2的第j-1个字符// 如果两个字符相同if (char1 == char2) {// 如果当前的两个字符相同,则当前dp[i][j]应基于之前的dp[i-1][j-1]的值加1dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 如果两个字符不同,选择之前两种情况的较大者作为当前dp[i][j]的值dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}// 返回数组的最后一个元素,即为text1和text2的最长公共子序列长度return dp[text1.length()][text2.length()];}
}

二、不相交的线

1035.原题链接

它实质上和最长公共子序列(LCS)问题相同,只是在不同的上下文中应用。在这个问题中,我们要在两个数组中找到最多的对应数字(或线),使得这些数字的顺序在两个数组中保持一致,但不必连续。

2.1、动态规划五部曲

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

  • 其中 dp[i][j] 代表考虑 nums1 的前 i 个元素和 nums2 的前 j 个元素时的最大不相交线数(或最长公共子序列的长度)。

2.1.2、确定递推公式

  • for (int i = 1; i <= len1; i++):外层循环遍历 nums1
  • for (int j = 1; j <= len2; j++):内层循环遍历 nums2
    • if (nums1[i - 1] == nums2[j - 1]):如果当前考虑的两个元素相等,表示可以在此基础上形成一个新的对应线,所以 dp[i][j] = dp[i - 1][j - 1] + 1;。这意味着我们在之前的最大对应线数的基础上增加一条新的线。
    • else:如果当前的两个元素不相等,则我们需要决定是跳过 nums1 的当前元素还是 nums2 的当前元素,以保持最大的对应线数。因此,dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 选择这两种情况中较大的一个。

2.1.3、 dp数组如何初始化

根据前面的分析。dp 表的最后一个元素就是两个数组中可以形成的最大不相交线数,这等同于最长公共子序列的长度。所以初始化逻辑和上面那题是一样的,这里不再赘述了。

2.1.4、确定遍历顺序

从小到大遍历

2.1.5、输出结果

  • return dp[len1][len2]; 动态规划表的最后一个元素包含了整个 nums1nums2 可以形成的最大不相交线数。

2.2、代码

class Solution {// maxUncrossedLines 方法用来计算两个数组间的最大未交叉线数public int maxUncrossedLines(int[] nums1, int[] nums2) {// len1 和 len2 分别是两个数组的长度int len1 = nums1.length;int len2 = nums2.length;// dp 数组用于存储动态规划的中间结果int[][] dp = new int[len1 + 1][len2 + 1];// 外层循环遍历 nums1for (int i = 1; i <= len1; i++) {// 内层循环遍历 nums2for (int j = 1; j <= len2; j++) {// 如果当前两个数组的元素相等,更新 dp 数组的值if (nums1[i - 1] == nums2[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 如果不相等,取两种情况的较大值,即不包含当前 nums1 的元素或不包含当前 nums2 的元素dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}// 返回 dp 数组右下角的值,即为最大未交叉线数return dp[len1][len2];}
}

三、最大子序和

53.原题链接

3.1、动态规划五部曲

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

  • dp[i] 表示以第 i 个元素结尾的最大子数组和。

3.1.2、确定递推公式

  • 从数组的第二个元素开始遍历(即i=1)。
  • 对于每个元素nums[i],更新dp[i]。这里的转移方程是:
    • dp[i] = Math.max(dp[i-1] + nums[i], nums[i])
    • 这个方程的意思是,考虑到第i个元素时,最大子数组和可以是:
      • dp[i-1] + nums[i](即包含之前的最大子数组和再加上当前元素nums[i]),或者
      • nums[i]本身(即从新开始计数,只取当前元素,这种情况适用于dp[i-1]是负数,不如放弃之前的累计,重新开始)。
  • 同时更新结果res,如果dp[i]比当前的res还要大,就用dp[i]更新res

3.1.3、 dp数组如何初始化

dp[0]即为nums[0],因为第一个元素前面没有其他元素,所以它自身就是一个子数组。

3.1.4、确定遍历顺序

从小到大遍历

3.1.5、输出结果

最后返回 res,它存储的是整个数组的最大子数组和。

3.2、代码

class Solution {public int maxSubArray(int[] nums) {// 如果数组为空,则直接返回0(通常情况下,这里可以根据题意返回负无穷或抛出异常)if (nums.length == 0) {return 0;}// res用来存储最终的最大子数组和,初值设为数组的第一个元素int res = nums[0];// dp数组用于动态规划存储到当前元素为止的最大子数组和,dp[0]自然是第一个元素int[] dp = new int[nums.length];dp[0] = nums[0];// 从数组的第二个元素开始遍历for (int i = 1; i < nums.length; i++) {// 动态规划的转移方程:比较“继续当前子数组”与“从新的位置开始”dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);// 更新全局的最大子数组和res = Math.max(res, dp[i]);}// 返回计算得到的最大子数组和return res;}
}

总结

1.感想

  • 补周六的进度,冲

2.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

这篇关于代码随想录刷题day53|最长公共子序列不相交的线最大子序和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部