最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入:[10,9,2,5,3,7,101,18]输出: 4 解释: 最长的上升子序列是[2,3,7,101],它的长度是4。
说明:
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
思考: 要得到的是最长上升子序列的长度。
dp[ i ] 表示 前 i 个元素中,最长上升子序列的长度,那么 dp[ i+1 ] 的值 就要根据 nums[ i+1 ] 的值 和 子序列的最后一个值来确定。(子序列可能不止一个!!) ( 分析的不好!!! )
动态规划,为什么不是返回 dp 数组的最后一个元素呢? 因此这里的 dp[ i ]表示的是以 nums[ i ]作为上升子序列最后一个元素的 序列的长度。
( 用dp数组的时候,一定要明白数组的元素是什么意思,也就是数组的状态表示的是什么??? )
class Solution { public int lengthOfLIS(int[] nums) { if(nums==null||nums.length==0) return 0; int res=1; int[] dp = new int[nums.length]; for(int i=0;i<nums.length;i++){ dp[i]=1; } for(int i=0;i<nums.length;i++){ for(int j=0;j<i;j++){ if(nums[j]<nums[i]){ dp[i]=Math.max(dp[i],dp[j]+1); if(res<dp[i]) res=dp[i]; } } } return res; } }
怎么优化成 nlogn 呢? 看到 log n 就想到一般是用二分查找了!!!对于nums 数组的循环肯定是没法优化的,那么就是要去优化第二个循环了!
(可是第二个循环是无序的啊? 怎么用二分呢? 二分的前提是数组中的元素是有序的啊!!)
dp 远没有想像中的那么简单!!!
( 主要就是dp状态的选择和状态转移方程的确立! ) 这里的dp[ i ]表示的就是当前固定长度下的 长度为 i+1的子序列的最后一个元素的最小值。
class Solution { public int lengthOfLIS(int[] nums) { if(nums==null || nums.length==0) return 0; // dp[i] 表示前 i+1个元素的子序列的最小值 int[] dp = new int[nums.length]; dp[0]=nums[0]; int end = 0; for(int i=1;i<nums.length;i++){ if(nums[i]>dp[end]){ end++; dp[end]=nums[i]; }else{ int left=0,right=end; while(left<right){ int mid=left+((right-left)>>>1); if(dp[mid]<nums[i]) left=mid+1; else right=mid; } dp[left]=nums[i]; } } return ++end; } }
也许会有遗憾,但是不应该在失败之前
浙公网安备 33010602011771号