题目描述:

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

示例:

输入: [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. form表单提交后结果乱码的解决方法

    1.产生乱码原因:表单提交使用的method="get",get方式数据都是通过地址栏传输,数据会以iso-8859-1方式传输,因此产生乱码 2.概念:URI: Uniform ...

  2. bootstrap 模态框在iphone微信内点击无效

    <a  data-toggle="modal" data-target="#wwww" href=""  οnclick=" ...

  3. ubuntu打开终端

    虚拟终端 Ctrl+Alt+T组合键 实际终端 Ctrl+Alt+F1 ~ F6组合键 可以在登录界面直接切换 退出终端 Ctrl+Alt+F7组合键

  4. perl自定义简易的面向对象的栈与队列类

    perl中的数组其实已经具备了栈与队列的特点,下面是对数组经过一些封装的stack,queue对象 1.Stack类 创建一个Stack.pm文件 package Stack; sub new{ $s ...

  5. SAP官方提供的人脸识别API

    https://api.sap.com/api/face_detection_api/resource 准备一张克里斯蒂亚诺 - 罗纳尔多的图片: 点击Choose File按钮,加载这些图片,然后点 ...

  6. B+树Java代码实现以及测试

    M阶B+树的定义: 任意非叶子结点最多有M个子节点:且M>2: 除根结点以外的非叶子结点至少有 M/2个子节点: 根结点至少有2个子节点: 除根节点外每个结点存放至少M/2和至多M个关键字:(至 ...

  7. 【Struts2】Json插件使用

    一.使用步骤 1.1 引入依赖 1.2 在struts.xml文件中配置 一.使用步骤 1.1 引入依赖 <!-- https://mvnrepository.com/artifact/org. ...

  8. 【问题】redhat安装dig

    转自:https://blog.csdn.net/ricky_hust/article/details/8868131 最终可行的方法 在linux下没有单独的dig和nslookup的包,而是以bi ...

  9. linux 基础12-程序与资源管理

    1. 基础概念 可执行的二进制文件就是程序 执行程序的时候因触发事件而获取的ID,称为PID 在登入并执行bash时,系统依据登录者的UID/GID给登录者一个PID/GPID/SID等 启动程序时, ...

  10. Java 基础 - Set接口 及其实现类HashSet/LinkedHashSet/TreeSet

    笔记: /**Set接口 及其实现类 * 公用操作同Collection: * * ①size(),clear()②isEmpty(),③contains(),④add()方法 和remove()方法 ...