题目描述:

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明: 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

思路分析:(题解来自:https://leetcode-cn.com/u/liweiwei1419/

动态规划,时间复杂度为 O(N^2);

“动态规划”的两个步骤是思考“状态”以及“状态转移方程”。

有的资料又将“动态规划”分为 3 步:

base case:思考问题规模最小的时候,是什么情况;
update function:自下而上思考这个问题,即上面的“状态转移方程”;
gola:重点强调了输出是什么,很多时候输出并不一定是最后一个状态。
我觉得这种分法更细致一点,“状态”以及“状态转移方程”也没有问题,但是我觉得还要加上一个,思考一下“输出”是什么,即将第 2 种的第 3 步加上去,在下面的分析中,我还会强调这一点。

1、定义状态

首先我们考虑能否将题目的问法定义成状态,即 dp[i] 表示长度为 i 的最长上升子序列的长度,但仔细思考之后,我们发现:由于“子序列”不要求连续,长度为 i - 1 的最长上升子序列,与长度为 i 的“最长上升子序列之间的递推关系并不那么容易得到。

但我们由「力扣」第 3 题:“无重复字符的最长子串”以及「力扣」第 53 题:“最大子序和”这两个问题的经验,再结合题意,可以知道,“上升”的递推关系是:看子序列最后一个数,如果一个新数,比子序列最后一个数还大,那么就可以放在这个子序列的最后,形成一个更长的子序列。反正一个子序列一定会以一个数字结尾,那我就将状态成以 nums[i] 结尾的“最长上升子序列”的长度,这一点是常见的。

dp[i]:表示以第 i 个数字为结尾的“最长上升子序列”的长度。即在 [0, ..., i] 的范围内,选择 以数字 nums[i] 结尾 可以获得的最长上升子序列的长度。注意:以第 i 个数字为结尾,即 要求 nums[i] 必须被选取。

初始化的时候,因为每个元素自己可以认为是一个长度为 1 的子序列,所以可以将 dp 数组的值全部设置为 1。

定义输出:下面要考虑一下输出,由于状态不是题目中的问法,因此不能将最后一个状态作为输出,这里输出是把 dp[0]、dp[1]、……、dp[n - 1] 全部看一遍,取最大值。

2、推导“状态转移方程”

遍历到索引是 i 的数的时候,根据上面“状态”的定义,考虑把 i 之前的所有的数都看一遍,只要当前的数 nums[i] 严格大于之前的某个数,那么 nums[i] 就可以接在这个数后面形成一个更长的上升子序列。因此,dp[i] 就是之前严格小于 nums[i] 的“状态”最大值加 1。

因此,状态转移方程是:

dp[i] = max{1 + dp[j] for j < i if nums[j] < nums[i]}

代码实现:

class Solution {
public static int lengthOfLIS(int[] nums) { int len = nums.length;
int[] dp = new int[len];
Arrays.fill(dp, 1);
//初始化dp数组,每个元素至少都是以它自身为结尾,长度为1的自序列
int maxLen = 0;
//从第二个元素开始
for (int i = 1; i < len; i++) {
//以当前元素为结尾
int curVal = nums[i];
for (int j = 0; j < i; j++) {
//当前元素严格大于之前的任何一个片段,则当前元素都可以加在这个区间后面,形成+1长度的自序列
if (curVal > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
for (int element : dp) {
maxLen = Math.max(maxLen, element);
}
return maxLen;
}
}

时间复杂度:O(n^2)

空间复杂度:O(n)

Leetcode题目300.最长上升子序列(动态规划-中等)的更多相关文章

  1. 【LeetCode】300.最长递增子序列——暴力递归(O(n^3)),动态规划(O(n^2)),动态规划+二分法(O(nlogn))

    算法新手,刷力扣遇到这题,搞了半天终于搞懂了,来这记录一下,欢迎大家交流指点. 题目描述: 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度. 子序列是由数组派生而来的序列,删除(或不删 ...

  2. [LeetCode] 300. 最长上升子序列 ☆☆☆(动态规划 二分)

    https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-she-ji-fan ...

  3. Leetcode题目64.最小路径和(动态规划-中等)

    题目描述: 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入: [ [1,3,1], [1, ...

  4. Leetcode——300. 最长上升子序列

    题目描述:题目链接 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101], ...

  5. Java实现 LeetCode 300 最长上升子序列

    300. 最长上升子序列 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,10 ...

  6. 1. 线性DP 300. 最长上升子序列 (LIS)

    最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...

  7. LeetCode 300. 最长上升子序列(Longest Increasing Subsequence)

    题目描述 给出一个无序的整形数组,找到最长上升子序列的长度. 例如, 给出 [10, 9, 2, 5, 3, 7, 101, 18], 最长的上升子序列是 [2, 3, 7, 101],因此它的长度是 ...

  8. LeetCode 300——最长上升子序列

    1. 题目 2. 解答 2.1. 动态规划 我们定义状态 state[i] 表示以 nums[i] 为结尾元素的最长上升子序列的长度,那么状态转移方程为: \[state[i] = max(state ...

  9. leetcode 300最长上升子序列

    用递归DFS遍历所有组合肯定积分会超时,原因是有很多重复的操作,可以想象每次回溯后肯定会有重复操作.所以改用动态规划.建立一个vector<int>memo,初始化为1,memo[i]表示 ...

随机推荐

  1. 关于ECharts甘特图的实现

    对于使用ECharts图表的步骤,每种图表都是一致的,相信大家也都了解 此处只分享甘特图的option,代码如下: option: { title: { text: '项目实施进度表', left: ...

  2. js循环及for-in , for-of的区别

    循环 字符串遍历:可通过for-of遍历字符串 for-in:遍历对象自身可继承可枚举属性 Object.keys():返回对象自身可枚举属性的键组成的数组 Object.getOwnProperty ...

  3. sql server存储过程返回数据只有一个字符

    SqlParameter[] param = { new SqlParameter("@shopId",shopId), new SqlParameter("@newSh ...

  4. dockerfile构建nginx

    mkdir docker_demo cd docker_demo wget http://nginx.org/download/nginx-1.2.9.tar.gz vim Dockerfile FR ...

  5. 一组简单好看的css3渐变按钮

    主要代码如下: body { background:#fff } /* Mixins */ /* bg shortcodes */ .bg-gradient1 span,.bg-gradient1:b ...

  6. 【leetcode】610. Triangle Judgement

    原题 A pupil Tim gets homework to identify whether three line segments could possibly form a triangle. ...

  7. 【问题】Difference between ">/dev/null 2>&1" and "2>&1 >/dev/null"

    https://www.unix.com/shell-programming-and-scripting/125947-difference-between-dev-null-2-1-2-1-dev- ...

  8. Cisco建网3层模型

    网络畅通条件: 沿途路由器必须知道到达目标网络下一跳给谁 沿途路由器必须知道回来的数据包下一跳给谁 Router0~2均手动添加了到192.168.1.0/24网段的路由 分析1:PC0 ping B ...

  9. openssl/opensslv.h错误的解决方案

    sudo apt install libssl-dev  

  10. FreeRTOS调度器

    FreeRTOS----调度器 调度器的启动流程分析 当创建完任务之后,会调用vTaskStartScheduler()函数,启动任务调度器: void vTaskStartScheduler( vo ...