300.最长递增子序列

目录

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
 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

## 题解

动态规格适用于
- 多阶段决策问题
- 不问具体解,只求最优解

**确定dp数组及其下标的含义**

> 第一次做我是没想出定义时为什么要以nums[i]结尾,看题解也没有想出个所以然。这里先了解,定义dp数组之后后面就好做多了。
![](https://www.icode9.com/i/l/?n=20&i=blog/1345685/202111/1345685-20211103120913727-1585978424.png)

dp[i] = 以nums[i]结尾的数组最长严格子序列长度为dp[i]

**确定递推式**
当前元素是nums[i],dp[i]如何推出?
- 如果nums[i]>nums[i-1],dp[i] = dp[i-1]+1;
- 如果nums[i]<=nums[i-1],dp[i] = dp[i-1];

开始是上面那样想的是因为对dp数组的定义有问题,然后报错之后发现
不应该只比较nums[i-1],因为我们**维护的是最长的子序列**,我们应该判断当前nums[i]与之前的最长递增子序列最后一个元素,最长递增子序列的最后一个元素不一定是nums[i-1]。
那么最长子序列的最后一个元素是什么呢?在i之前的每一个元素都有可能是最长子序列的最后一个元素。
所以与nums[j]比较,其中j<i,如果nums[i]>nums[j],说明当前元素可以加入以nums[j]结尾的最长递增子序列后面构成新的,dp[i] = dp[j]+1。
对于当前dp[i],不断地和dp[j]+1比较,寻找最大值 nums[i]>nums[j],dp[i] = Math(dp[i],dp[j]+1);

**dp数组初始化**
以nums[i]结尾的最长子序列至少要包含自己,那么dp数组初始化应该为1

**确定遍历顺序**

```java
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);
  }
  if(result>dp[i]) result = dp[i];
}

代码

class Solution {
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        if(len<=1) return 1;
        int dp[] = new int [len];
        dp[0] = 1;
        int result = 0;
            for(int i=1;i<nums.length;i++){
            dp[i] = 1;
            for(int j=0;j<i;j++){
            if(nums[i]>nums[j]) dp[i]= Math.max(dp[i],dp[j]+1);
          }
          if(dp[i]>result) result = dp[i];
        }
        return result;

    }
}

子序列问题

子序列问题

  • 子序列(不连续)
  • 子序列(连续)
  • 编辑距离
  • 回文
上一篇:300. 最长递增子序列 (动态规划)


下一篇:洛谷——P1089 [NOIP2004 提高组] 津津的储蓄计划