This commit is contained in:
programmercarl
2022-12-20 15:33:57 +08:00
parent 5fc31873aa
commit 77f1c528b7
15 changed files with 290 additions and 292 deletions

View File

@@ -14,17 +14,17 @@
示例 1
输入nums = [10,9,2,5,3,7,101,18]
输出4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
* 输入nums = [10,9,2,5,3,7,101,18]
* 输出4
* 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2
输入nums = [0,1,0,3,2,3]
输出4
* 输入nums = [0,1,0,3,2,3]
* 输出4
示例 3
输入nums = [7,7,7,7,7,7,7]
输出1
* 输入nums = [7,7,7,7,7,7,7]
* 输出1
提示:
@@ -33,11 +33,21 @@
## 思路
最长上升子序列是动规的经典题目这里dp[i]是可以根据dp[j] j < i推导出来的那么依然用动规五部曲来分析详细一波
首先通过本题大家要明确什么是子序列,“子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序”。
本题也是代码随想录中子序列问题的第一题,如果没接触过这种题目的话,本题还是很难的,甚至想暴力去搜索也不知道怎么搜。
子序列问题是动态规划解决的经典问题当前下标i的递增子序列长度其实和i之前的下表j的子序列长度有关系那那又是什么样的关系呢。
接下来,我们依然用动规五部曲来分析详细一波:
1. dp[i]的定义
**dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度**
本题中正确定义dp数组的含义十分重要。
**dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度**
为什么一定表示 “以nums[i]结尾的最长递增子序” ,因为我们在 做 递增比较的时候,如果比较 nums[j] 和 nums[i] 的大小那么两个递增子序列一定分别以nums[j]为结尾 和 nums[i]为结尾, 要不然这个比较就没有意义了,不是尾部元素的比较那么 如果算递增呢。
2. 状态转移方程
@@ -49,13 +59,15 @@
3. dp[i]的初始化
每一个i对应的dp[i](即最长上升子序列起始大小至少都是1.
每一个i对应的dp[i](即最长递增子序列起始大小至少都是1.
4. 确定遍历顺序
dp[i] 是有0到i-1各个位置的最长升序子序列 推导而来那么遍历i一定是从前向后遍历。
dp[i] 是有0到i-1各个位置的最长递增子序列 推导而来那么遍历i一定是从前向后遍历。
j其实就是0到i-1遍历i的循环在外层遍历j则在内层代码如下
j其实就是遍历0到i-1那么是从前到后,还是从后到前遍历都无所谓,只要吧 0 到 i-1 的元素都遍历了就行了。 所以默认习惯 从前向后遍历。
遍历i的循环在外层遍历j则在内层代码如下
```CPP
for (int i = 1; i < nums.size(); i++) {