最长子序列问题看得最懂的一集!(Java版)

近期做十四届蓝桥杯真题,遇到好多类似子序列的题目,发现还是不会做,于是乎回来再做一遍代码随想录相关题目,回来总结一下这几道题子序列问题(300. 最长递增子序列674. 最长连续递增序列718. 最长重复子数组)。接下来的总结,先给出代码,代码中有详细注释,根据代码随想录中的动态规划五部曲,对每一步做出自己的理解,最后来个总的汇总。

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数组的定义

关于dp数组的定义,首先应该确定维度

确定dp维度

一般根据所给数据的维度确定dp的维度。那这道题明显dp为1维。这毕竟是普遍的规律,当然,其实还得看题目问什么。那到底怎么看呢?这里我总结的规律是:

先分析问题,将问题简单化,然后抓住所给数据的某个数,对它进行提问,去思考解决刚刚那个简单的问题:“它跟哪几个维度的数据匹配能得到(简单问题的)答案”。有几维的数据,就有几维dp。

有点抽象,例如本题,简单化,其实困扰我们的无非就是如何找递增的子序列长度,最大的问题可以先不管,拿样例1中的nums[3](数字5)进行提问:5与谁匹配能成为递增的子序列?是不是要么跟5前面小于5的数匹配成为一个递增的子序列,要么跟5后面小于5的数匹配成为一个递增的子序列(往往不往后匹配),那不管往前往后,都还是与5同一个维度吧,所以dp只需要一维就足够了。

确定dp[i]的定义

上面还只是确定维度,那dp[i]如何定义呢?根据一般子序列的规律,都是:

“以xxx结尾的,最大的xxx。”都是以某几个数字结尾的xxx

那到底应该怎么定义的呢?我的理解是(尽力解释了,这个东西是真的抽象):其实在确定维度的时候,就已经把dp[i]的计算方法确定了:就是定住nums[i]去比较它前面的第j个(j < i)是否有小于它小于它则dp[i]等于dp[j] + 1。即dp[i]定义为:dp[i]表示的就是 0~i中,以nums[i]结尾的最大子序列长度。

2.  递推公式的确定

其实在上面思考dp应该如何定义的时候,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值