严格递增

最长递增子序列,给定一个无序整数数组nums(字符串也可以,不重要),给出最长严格递增子序列的长度。比如输入[1, 2 , 1, -1, 1, 4, 0],输出3,最长递增子序列[1, 2, 4],当然可能不唯一,[-1, 1, 4]也是一个,但是并不影响长度。
强行遍历就不说了,时间复杂度O(2^n),简直爆炸。
思路1:动态规划,建立一个数组dp,dp[i]记录nums[0:i]的最长递增子序列的长度。
dp[i]=max(dp[j]+1),j∈{j∣nums[j]&lt;nums[i],0&lt;=j&lt;i}dp[i] = max(dp[j]+1),j∈\{ j | nums[j] &lt; nums[i], 0 &lt;= j &lt; i\} dp[i]=max(dp[j]+1),j∈{j∣nums[j]<nums[i],0<=j<i}
输出max(dp)即可,时间复杂度O(n^2),空间复杂度O(n)。

public int maxLengthCSub(int[] nums) {if(nums == null) {return 0;}int len = nums.length;if(len == 0 || len == 1) {return len;}int maxLen = 1;int[] dp = new int[len];for(int i = 0; i < len; 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);  // 更新dp[i]maxLen = Math.max(maxLen, dp[i]);  // 更新最大值}}}return maxLen;
}

思路2:动态规划+二分查找
同样建立一个数组dp,但是这里dp记录的是上升子序列,遍历nums室,用nums的元素填充dp,填充规则是什么呢?首先利用二分查找找到nums[i]在dp中应该插入的位置j,若j==当前dp的长度,则在dp末尾插入nums[i],maxLen加一,否则dp[j]=nums[i]。这里可能有个疑问,比如说nums[i0]=1放入dp[1],在后面的遍历中有一个nums[i1]=-1也需要放入dp[1],此时不会影响长度的计算吗?答案是不会,用一个例子比较容易理解。

input:[1, 2 , 1, -1, 1, 4, 0]
dp:[1], maxLen = 1
dp:[1, 2], maxLen = 2
dp:[1, 2], maxLen = 2
dp:[-1, 2], maxLen = 2
dp:[-1, 1], maxLen = 2
dp:[-1, 1, 4], maxLen = 3
dp:[-1, 0, 4], maxLen = 3

这里[-1, 0, 4]虽然不是一个最长递增子序列,但是并不会影响maxLen的值。
时间复杂度O(nlgn),空间复杂度O(n)。

public int maxLengthCSub(int[] nums) {if(nums == null) {return 0;}if(nums.length == 0 || nums.length == 1){return nums.length;}int[] dp = new int[nums.length];int maxLen = 0;for(int i = 0; i < nums.length; i++){int index = findIndex(dp, maxLen, nums[i]);dp[index] = nums[i];if(index == maxLen)maxLen++;}return maxLen;
}
// 二分查找,找到target在nums[0:len-1]的插入位置
public int findIndex(int[] nums, int len, int target){if(len == 0)return 0;int low = 0;int high = len;if(target <= nums[low])return 0;if(target > nums[len-1])return len;while(low < high){int middle = low + (high-low)/2;if(target > nums[middle]) // 右边low = middle + 1;else high = middle;}return low;
}

非严格递增

思路1:同严格递增的思路1,只需要在比较的时候加个等号:
dp[i]=max(dp[j]+1),j∈{j∣nums[j]&lt;=nums[i],0&lt;=j&lt;i}dp[i] = max(dp[j]+1),j∈\{ j | nums[j] &lt;= nums[i], 0 &lt;= j &lt; i\} dp[i]=max(dp[j]+1),j∈{j∣nums[j]<=nums[i],0<=j<i}
思路2:基本类似严格递增的思路1,但是这里插入的规则是要变的,不再是用二分查找插入dp,其插入位置要保证
dp[i−1]&lt;=dp[i]&lt;dp[i+1]dp[i-1] &lt;= dp[i] &lt; dp[i+1] dp[i−1]<=dp[i]<dp[i+1]
边界情况这里就不分析了,程序里也不需要进行分析,只需要求出i即可,同样求出i==maxLen,maxLen加一。还是通过一个例子来看。

input:[1, 2 , 1, -1, 1, 4, 0]
dp:[1], maxLen = 1
dp:[1, 2], maxLen = 2
dp:[1, 1], maxLen = 2
dp:[-1, 1], maxLen = 2
dp:[-1, 1, 1], maxLen = 3
dp:[-1, 1, 1, 4], maxLen = 4
dp:[-1, 0, 1, 4], maxLen = 4

看出不一样来了吧,主要是1的插入位置,不在是替换掉前面的1,而是在前面的1的后面放入新的1。

public int maxLengthCSub(int[] nums) {if(nums == null) {return 0;}int len = nums.length;if(len == 0 || len == 1) {return len;}int[] dp = new int[len];int maxLen = 0;for(int i = 0; i < len; i++) {int tmp = findIndex(dp, maxLen, nums[i]); // 无重复数字时的插入位置int tmp2 = findRIndex(dp, tmp, nums[i]);  // 有重复数字时的插入位置tmp = tmp2 == -1 ? tmp:tmp2;dp[tmp] = nums[i];if(tmp == maxLen)maxLen++;}return maxLen;}
// 同严格递增
// 二分查找,找到target在nums[0:len-1]的插入位置
public int findIndex(int[] nums, int len, int target){if(len == 0)return 0;int low = 0;int high = len;if(target <= nums[low])return 0;if(target > nums[len-1])return len;while(low < high){int middle = low + (high-low)/2;if(target > nums[middle]) // 右边low = middle + 1;else high = middle;}return low;
}
// 返回-1时,正常使用二分查找即可
public int findRIndex(int[] nums, int low, int tar) {if(low >= nums.length || low < 0)return -1;if(nums[low] != tar) { // 说明没有重复值return -1;}int high = low + 1;while(high < nums.length && nums[high] == nums[low]) {high++;}return high;
}

严格递增和非严格递增最长递增子序列长度相关推荐

  1. 51nod1134最长递增子序列(dp)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134 这里说下,最长上升子序列和最长不降子序列几乎一样,只是判 ...

  2. 【刷题】LOJ 6005 「网络流 24 题」最长递增子序列

    题目描述 给定正整数序列 \(x_1 \sim x_n\) ,以下递增子序列均为非严格递增. 计算其最长递增子序列的长度 \(s\) . 计算从给定的序列中最多可取出多少个长度为 \(s\) 的递增子 ...

  3. 最长递增子序列 最长连续递增序列

    引言 这两道题有很大的相似性,在这里主要的地方就是循环的设置,不仅仅适用于这两道题,在很多类似的题目中都可以用到,要学会相应的方法才行: 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格 ...

  4. 动态规划算法-04最长递增子序列问题

    最长递增子序列问题 简述 经典的动态规划问题. 问题描述 给定一个序列,求解其中长度最长的递增子序列. 问题分析 这种可以向下查询答案的很容易想到动态规划的解法. 要求长度为i的序列Ai={a1,a2 ...

  5. 耐心排序之最长递增子序列(LIS)

    目录 一.问题引入 1.最长递增子序列(LIS) 2.问题分析 3.代码实现 4.问题思考 二.耐心排序 1.基本介绍 2.操作步骤 3.代码实现 三.俄罗斯套娃信封问题 1.题目描述 2.问题分析 ...

  6. 动态规划算法04-最长递增子序列问题

    最长递增子序列问题 简述 经典的动态规划问题. 问题描述 给定一个序列,求解其中长度最长的递增子序列. 问题分析 这种可以向下查询答案的很容易想到动态规划的解法. 要求长度为i的序列Ai={a1,a2 ...

  7. 【LeetCode 二分查找专项】最长递增子序列(300)(to be polished...)

    文章目录 1. 题目 1.1 示例 1.2 说明 1.3 提示 1.4 进阶 2. 解法一(动态规划) 2.1 分析 2.2 解答 2.3 复杂度 3. 解法二(二分查找) 3.1 分析 3.2 解答 ...

  8. 最长递增子序列问题的求解

    一, 最长递增子序列问题的描述 设L=<a1,a2,-,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,-,akm>,其中k1<k2 ...

  9. 动态规划(最长递增子序列)---最长递增子序列

    最长递增子序列 300. Longest Increasing Subsequence (Medium) 题目描述:   给定一个数组,找到它的最长递增子序列 思路分析:   动态规划思想,定义一个数 ...

最新文章

  1. Java_bytecode
  2. skimage库安装
  3. 10.19 qbxt国庆day3
  4. 纯java应用搭建,16、BoneCp纯java项目使用
  5. TCP BBR - 如何安装、启动、停止BBR!
  6. ASP.NET项目中的驼峰格式JSON响应
  7. java jtextfield 事件_java – 处理JTextField中的编辑事件
  8. 苹果iPhone XI新爆料:用了被小米当噱头的TOF技术
  9. c语言switch工资怎么弄,超级新手,用switch写了个计算器程序,求指导
  10. #include stdafx.h
  11. 语义替换脚本——论文降重GUI
  12. 8个优质自学网站收藏
  13. Android 百分比布局库(percent-support-lib) 解析与扩展
  14. vue引入Echarts画饼图详解
  15. 基于ensp的网络设计【实现网络互联、限制访问、内外网地址转换】
  16. 2018王鼎杯-fakebook-详细解说
  17. 结构-02. 有理数加法
  18. 马云布局大阿里蓝图:美好但需跋涉
  19. 面试别向HR说这六种离职原因
  20. 为什么 头条 宇宙条_为什么美团被戏称为“开水团”,头条则被封为“宇宙条”?...

热门文章

  1. 前后端分离实现图片上传的功能
  2. 熊分享-负重前行有我陪伴!
  3. 365值得吗 office_你可能是正版受害者?吐槽Office 365坑爹之处
  4. 鸿蒙系统可以跟ios媲美吗,华为鸿蒙三年媲美苹果iOS?技术上问题不大,生态才是真正考验...
  5. multisim14晶振在哪里_石英晶振在multisim中哪里
  6. DOTA2无法找到有效的direct 3D
  7. Sklearn机器学习中的主要算法原理以及实现
  8. Oracle-11:联合查询
  9. 【迅为iMX6Q】开发板:uboot-imx编译
  10. Agilent E4407B/安捷伦E4407B频谱分析仪