【问题描述】[中等]

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

【解答思路】

1. 动态规划




时间复杂度:O(N^2) 空间复杂度:O(N)

import java.util.Arrays;public class Solution {public int lengthOfLIS(int[] nums) {int len = nums.length;if (len < 2) {return len;}int[] dp = new int[len];Arrays.fill(dp, 1);for (int i = 1; i < len; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}}int res = 0;for (int i = 0; i < len; i++) {res = Math.max(res, dp[i]);}return res;}
}
2. 动态规划压缩空间(贪心+二分)






时间复杂度:O(NlogN) 空间复杂度:O(N)

public class Solution {public int lengthOfLIS(int[] nums) {int len = nums.length;if (len <= 1) {return len;}// tail 数组的定义:长度为 i + 1 的上升子序列的末尾最小是几int[] tail = new int[len];// 遍历第 1 个数,直接放在有序数组 tail 的开头tail[0] = nums[0];// end 表示有序数组 tail 的最后一个已经赋值元素的索引int end = 0;for (int i = 1; i < len; i++) {// 【逻辑 1】比 tail 数组实际有效的末尾的那个元素还大if (nums[i] > tail[end]) {// 直接添加在那个元素的后面,所以 end 先加 1end++;tail[end] = nums[i];} else {// 使用二分查找法,在有序数组 tail 中// 找到第 1 个大于等于 nums[i] 的元素,尝试让那个元素更小int left = 0;int right = end;while (left < right) {// 选左中位数不是偶然,而是有原因的,原因请见 LeetCode 第 35 题题解// int mid = left + (right - left) / 2;int mid = left + ((right - left) >>> 1);if (tail[mid] < nums[i]) {// 中位数肯定不是要找的数,把它写在分支的前面left = mid + 1;} else {right = mid;}}// 走到这里是因为 【逻辑 1】 的反面,因此一定能找到第 1 个大于等于 nums[i] 的元素// 因此,无需再单独判断tail[left] = nums[i];}// 调试方法// printArray(nums[i], tail);}// 此时 end 是有序数组 tail 最后一个元素的索引// 题目要求返回的是长度,因此 +1 后返回end++;return end;}// 调试方法,以观察是否运行正确private void printArray(int num, int[] tail) {System.out.print("当前数字:" + num);System.out.print("\t当前 tail 数组:");int len = tail.length;for (int i = 0; i < len; i++) {if (tail[i] == 0) {break;}System.out.print(tail[i] + ", ");}System.out.println();}public static void main(String[] args) {int[] nums = new int[]{3, 5, 6, 2, 5, 4, 19, 5, 6, 7, 12};Solution solution = new Solution8();int lengthOfLIS = solution8.lengthOfLIS(nums);System.out.println("最长上升子序列的长度:" + lengthOfLIS);}
}

【总结】

1.子序列和子串


2.动态规划(高度概括)

第 1 步:设计状态
第 2 步:状态转移方程
第 3 步:考虑初始化
第 4 步:考虑输出
第 5 步:考虑是否可以状态压缩

3.动态规划(详细说明)

1、思考状态(重点)

状态的定义,先尝试「题目问什么,就把什么设置为状态」;
然后思考「状态如何转移」,如果「状态转移方程」不容易得到,尝试修改定义,目的依然是为了方便得到「状态转移方程」。
「状态转移方程」是原始问题的不同规模的子问题的联系。即大问题的最优解如何由小问题的最优解得到。

2、思考状态转移方程(核心、难点)

状态转移方程是非常重要的,是动态规划的核心,也是难点;

常见的推导技巧是:分类讨论。即:对状态空间进行分类;

归纳「状态转移方程」是一个很灵活的事情,通常是具体问题具体分析;

除了掌握经典的动态规划问题以外,还需要多做题;

如果是针对面试,请自行把握难度。掌握常见问题的动态规划解法,理解动态规划解决问题,是从一个小规模问题出发,逐步得到大问题的解,并记录中间过程;

「动态规划」方法依然是「空间换时间」思想的体现,常见的解决问题的过程很像在「填表」。

3、思考初始化

初始化是非常重要的,一步错,步步错。初始化状态一定要设置对,才可能得到正确的结果。

角度 1:直接从状态的语义出发;

角度 2:如果状态的语义不好思考,就考虑「状态转移方程」的边界需要什么样初始化的条件;

角度 3:从「状态转移方程」方程的下标看是否需要多设置一行、一列表示「哨兵」(sentinel),这样可以避免一些特殊情况的讨论。

4、思考输出

有些时候是最后一个状态,有些时候可能会综合之前所有计算过的状态。

5、思考优化空间(也可以叫做表格复用)

「优化空间」会使得代码难于理解,且是的「状态」丢失原来的语义,初学的时候可以不一步到位。先把代码写正确是更重要;
「优化空间」在有一种情况下是很有必要的,那就是状态空间非常庞大的时候(处理海量数据),此时空间不够用,就必须「优化空间」;
非常经典的「优化空间」的典型问题是「0-1 背包」问题和「完全背包」问题。

4. 动态规划思考
  • 边界问题考虑清楚(第二第三步)
  • 动态就是做表格 想清楚方向
  • 自底向上 子问题 学基础 再解决问题 通识教育
  • 自顶向下 一般解决问题思路

转载链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/

[Leedcode][JAVA][第300题][最长上上子序列][动态规划][压缩空间]相关推荐

  1. [剑指offer]面试题第[42]题[Leedcode][JAVA][第53题][最大子序和][动态规划][贪心][分治]

    [问题描述][第53题][最大子序和][中等] 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和.示例:输入: [-2,1,-3,4,-1,2,1, ...

  2. [Leedcode][JAVA][第887题][鸡蛋掉落][谷歌面试][动态规划]

    [问题描述] [887. 鸡蛋掉落] 你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑.每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去.你知道存在楼层 F ,满足 ...

  3. [Leedcode][JAVA][第22题括号生成][DFS][BFS][动态规划]

    [问题描述]22. 括号生成 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例:输入:n = 3 输出:["((()))",&q ...

  4. [Leedcode][JAVA][第152题][乘积最大子数组][动态规划]

    [问题描述][中等] 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积.示例 1:输入: [2,3,-2,4] 输出: 6 解 ...

  5. [Leedcode][JAVA][第105题][从前序与中序遍历序列构造二叉树][栈][递归][二叉树]

    [问题描述][中等] 根据一棵树的前序遍历与中序遍历构造二叉树.注意: 你可以假设树中没有重复的元素.例如,给出前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = ...

  6. [Leedcode][JAVA][第470题][Ran7()实现Rand10()]

    [问题描述][Leedcode][JAVA][第470题][Ran7()实现Rand10()] 已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 ...

  7. [Leedcode][JAVA][第45题][跳跃游戏 II][贪心算法]

    [问题描述][Leedcode][JAVA][第45题][跳跃游戏 II] 输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2.从下标为 0 跳到下标为 1 的位置 ...

  8. 最新Java面试300题:腾讯T4面试+美团+京东+拼多多(文末答案附赠)

    数据库原理 MYISAM与innodb搜索引擎原理MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址.其采用索引文件与数据文件,索引文件只存放索引,叶子节点存放数据 ...

  9. 十月常见算法考题、最长递增子序列,Leetcode第300题最长上升子序列的变种,我没见过乔丹,今天詹姆斯就是我的神!

    @Author:Runsen @Date:2020/10/12 十月过得很平缓.在这个"收获的季节",我成了为数不多不必收获的人.每天睡到中午,即使闹钟设在早上也很难把自己弄醒. ...

最新文章

  1. 450. 删除二叉搜索树中的节点
  2. 万字长文了解免疫算法原理 及求解复杂约束问题(源码实现)
  3. 程序员需要关注的十个大数据技术
  4. Win-MASM64汇编语言-ADD/SUB/INC自增/DEC自减
  5. 3位创业公司CEO亲述:200人的小公司,这么做数据管理就对了
  6. HashMap遍历有序性问题——map.entrySet()的无序性
  7. python地图热力图是什么意思_python热力图
  8. 西华大学c语言考试题,西华大学C语言程序设计复习题
  9. Pytorch使用tensorboardX可视化
  10. iconfont阿里巴巴矢量图标库使用步骤
  11. JavaScript获取当前url路径
  12. php千月影视,千月影视双端源码完美运营新手搭建教程
  13. 汇川,H3U,plc程序模板和触摸屏程序模板,三个步进和三个伺服,三个伺服用的是canlink总线,适用于运动轴控制
  14. MySql5.7 + Linux 修改数据库密码
  15. 卡尔曼滤波原理及matlab仿真
  16. 双非本科生进大厂,而我还在底层默默地爬树(上)
  17. Docker基础、利用Docker Compose部署Vue项目
  18. TOF飞行时间深度相机介绍
  19. 电脑重要文件如何实现增量备份?
  20. java ftp 被动模式_ftp 主动模式与被动模式

热门文章

  1. C#对用户密码使用MD5加密与解密
  2. 排错“未能封送类型,因为嵌入数组实例的长度与布局中声明的长度不匹配”...
  3. HADOOP__PIG安装与配置
  4. MSMQ(MicroSoft Message Queue,微软消息队列)
  5. Java2实用教程(第二版)程序代码——第十四章 Component类的常用方法
  6. python二级简书_12月4日,总结发现杯,备战python二级
  7. hession调用json解析异常 com.caucho.hessian.io.HessianProtocolException: expected integer at 0x74 java.util
  8. 悦虎144固件,华强北二代悦虎144固件,1562M芯片144固件
  9. 微信支付—微信H5支付「非微信内部浏览器-QQ/UC浏览器等」
  10. Android 抖动提示动画