题目描述
难点在于时间复杂度 O(n * logn)的做法
思路 & 代码
动态规划 O(n2n^2 n 2 )
先抛砖引玉啦~ dp[i]:以 nums[i] 结尾的子序列,能达到的最大长度 对于 dp[i] 来说,只要找到前面的比 nums[i] 小的 nums[j] 中最大的 dp[j] 即可
class Solution { public int lengthOfLIS ( int [ ] nums) { int len = nums. length; int ans = 1 ; int [ ] dp = new int [ len] ; dp[ 0 ] = 1 ; for ( int i = 1 ; i < len; i++ ) { int maxPre = 0 ; for ( int j = i - 1 ; j >= 0 ; j-- ) { if ( nums[ i] > nums[ j] ) { maxPre = Math . max ( dp[ j] , maxPre) ; } } dp[ i] = maxPre + 1 ; ans = Math . max ( ans, dp[ i] ) ; } return ans; }
}
动态规划 + 二分法 + 贪心 O(nlognnlogn n l o g n )
新定义 tail[i]:代表长度为 i + 1 的递增子序列的最小尾值 详见注释。建议还是看看这篇题解,结合里面的动图会更好地理解这道题。
class Solution { public int lengthOfLIS ( int [ ] nums) { int len = nums. length; int [ ] tail = new int [ len] ; tail[ 0 ] = nums[ 0 ] ; int endIndex = 0 ; for ( int i = 1 ; i < len; i++ ) { if ( nums[ i] > tail[ endIndex] ) { tail[ ++ endIndex] = nums[ i] ; } else { int left = 0 , right = endIndex; while ( left < right) { int mid = left + ( right - left) / 2 ; if ( tail[ mid] < nums[ i] ) { left = mid + 1 ; } else { right = mid; } } tail[ left] = nums[ i] ; } } int ans = endIndex + 1 ; return ans; }
}
二刷
写不出 O(logN) 的,我还写不出你 O(n^2) 的吗! 10+ 行代码,还是挺清晰的,记得 dp[nums.length - 1] 不一定是最终答案噢~
class Solution { public int lengthOfLIS ( int [ ] nums) { int [ ] dp = new int [ nums. length] ; dp[ 0 ] = 1 ; int res = 1 ; for ( int i = 1 ; i < nums. length; i++ ) { int max = 0 ; for ( int j = 0 ; j < i; j++ ) { if ( nums[ j] < nums[ i] ) { max = Math . max ( max, dp[ j] ) ; } } dp[ i] = max + 1 ; res = Math . max ( res, dp[ i] ) ; } return res; }
}