Day51:动态规划 LeedCode 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

ops/2024/10/21 4:16:22/

300. 最长递增子序列

中等

相关标签

相关企业

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

提示:

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

思路:

动态规划五部曲:

1.dp[i]的定义

dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

2.状态转移方程

位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。

所以:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);

3.初始化

每一个i,对应的dp[i](即最长递增子序列)起始大小至少都是1.

为什么不仅仅设置dp[0]=1?

因为在之前有比当前nums[i]小的数时,dp[i]才被赋值,如果前面都没比nums[i]小的数,dp[i]就等于初始值,这个初始值应该为1,因为此时以Nums[i]结尾的子串长度为1

if(nums[i]>nums[j])
            dp[i]=Math.max(dp[i],dp[j]+1);

4.确定遍历顺序

dp[i] 是有0到i-1各个位置的最长递增子序列 推导而来,那么遍历i一定是从前向后遍历

5.举例

代码参考:

class Solution {public int lengthOfLIS(int[] nums) {int[] dp=new int[nums.length];//初始化for(int i=0;i<nums.length;i++){dp[i]=1;}for(int i=1;i<nums.length;i++){for(int j=0;j<i;j++){if(nums[i]>nums[j])dp[i]=Math.max(dp[i],dp[j]+1);}}//取最长长度int result=0;for(int i=0;i<dp.length;i++){result=Math.max(result,dp[i]);}return result;}
}

674. 最长连续递增序列

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

连续递增的子序列 可以由两个下标 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。

思路:

与上题相比,本题多了一个要求:连续!

动规五部曲分析如下:

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

dp[i]:以下标i为结尾连续递增的子序列长度为dp[i]

2.确定递推公式

如果 nums[i] > nums[i - 1],那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 + 1 。

即:dp[i] = dp[i - 1] + 1;

3.dp数组如何初始化

以下标i为结尾的连续递增的子序列长度最少也应该是1,即就是nums[i]这一个元素。

所以dp[i]应该初始1;

4.确定遍历顺序

dp[i + 1]依赖dp[i],所以一定是从前向后遍历

5.举例

代码参考:

class Solution {public int findLengthOfLCIS(int[] nums) {int[] dp=new int[nums.length];//初始化for(int i=0;i<nums.length;i++){dp[i]=1;}int result=1;for(int i=1;i<nums.length;i++){if(nums[i]>nums[i-1]){dp[i]=dp[i-1]+1;}result=Math.max(result,dp[i]);}return result;}
}

718. 最长重复子数组

给两个整数数组 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

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 100

思路:

动态规划五部曲:

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

dp[i][j] :以下标i 为结尾的A,和以下标j 为结尾的B,最长重复子数组长度为dp[i][j]。 

为什么用二维数组表示?

因为两个子串重复子串的位置在两个子串中可能不同

2.确定递推公式

当A[i ] 和B[j ]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;

3.dp数组如何初始化

dp[i][0] 和dp[0][j]都要初始化

   int result=0;for(int i=0;i<nums1.length;i++){if(nums1[i]==nums2[0]){dp[i][0]=1;}result=Math.max(result,dp[i][0]);}for(int i=0;i<nums2.length;i++){if(nums2[i]==nums1[0]){dp[0][i]=1;}result=Math.max(result,dp[0][i]);}

4.确定遍历顺序

外层for循环遍历A,内层for循环遍历B,互换也行

   for(int i=1;i<nums1.length;i++){for(int j=1;j<nums2.length;j++){if(nums1[i]==nums2[j]){dp[i][j]=dp[i-1][j-1]+1;}result=Math.max(result,dp[i][j]);}}

5.举例

代码参考:

class Solution {public int findLength(int[] nums1, int[] nums2) {int[][] dp=new int[nums1.length][nums2.length];//初始化int result=0;for(int i=0;i<nums1.length;i++){if(nums1[i]==nums2[0]){dp[i][0]=1;}result=Math.max(result,dp[i][0]);}for(int i=0;i<nums2.length;i++){if(nums2[i]==nums1[0]){dp[0][i]=1;}result=Math.max(result,dp[0][i]);}//更新dp数组and resultfor(int i=1;i<nums1.length;i++){for(int j=1;j<nums2.length;j++){if(nums1[i]==nums2[j]){dp[i][j]=dp[i-1][j-1]+1;}result=Math.max(result,dp[i][j]);}}return result;}
}


http://www.ppmy.cn/ops/15917.html

相关文章

代码随想录-算法训练营day23【二叉树09:修剪二叉搜索树、将有序数组转换为二叉搜索树、把二叉搜索树转换为累加树】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第六章 二叉树part09今日内容&#xff1a;● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇 详细布置 669. 修剪二叉搜索树 这道题目比较难&#xff0c;比 添…

2024深圳杯C题的8页思路分析+所有代码可执行+参考文献+持续更新参考论文(已经更新了代码与图像)

比赛题目的完整版思路可执行代码数据参考论文都会在第一时间更新上传的&#xff0c;大家可以参考我往期的资料&#xff0c;所有的资料数据以及到最后更新的参考论文都是一次付费后续免费的。注意&#xff1a;&#xff08;建议先下单占坑&#xff0c;因为随着后续我们更新资料数…

Leetcode双指针刷题(一)

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…

TDengine高可用架构之TDengine+Keepalived

之前在《TDengine高可用探讨》提到过&#xff0c;TDengine通过多副本和多节点能够保证数据库集群的高可用。单对于应用端来说&#xff0c;如果使用原生连接方式&#xff08;taosc&#xff09;还好&#xff0c;当一个节点下线&#xff0c;应用不会受到影响&#xff1b;但如果使用…

什么是方法重载和重写,区别是什么?

面试题目 什么是方法重载&#xff1f;什么是方法重写&#xff1f;方法重载和重写有什么区别&#xff1f;返回值不同算不算方法重载&#xff1f; 这个是对Java基础知识的考察&#xff0c;但我们要掌握的是写重载和重写方法有什么好处&#xff0c;为什么要这样写&#xff1f; …

常见的几种垃圾回收器

什么是垃圾回收器&#xff0c;可以这样理解&#xff0c;垃圾回收算法是概念理论&#xff0c;对应JAVA中的接口&#xff0c;垃圾回收器就是具体的实现&#xff0c;JVM有很多垃圾回收器&#xff0c;它们实现了不同的垃圾回收算法&#xff0c;可以用在不同jdk版本&#xff0c;也适…

分布式技术在文本摘要生成中的应用

摘要 自然语言处理首先要应对的是如何表示文本以供机器处理&#xff0c;随着网络技术的发展和信息的公开&#xff0c;因特网上可供访问的数字文档成爆炸式的增长&#xff0c;文本摘要生成逐渐成为了自然语言处理领域的重要研究课题。本文主要介绍了分布式技术在文本摘要生成中…

react之组件与JSX

第一章 - 描述用户界面 概述&#xff1a;React是一个用于构建用户界面&#xff08;UI&#xff09;的JavaScript库&#xff0c;用户界面由按钮&#xff0c;文本和图像等小单元内容构建而成。React帮助你把它们组合成可重用&#xff0c;可嵌套的组件。从web端网站到移动端应用&a…