给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-increasing-subsequence
1. 状态的说明:①到nums[i]处,最长子序列;②以nums[i]结尾,最长子序列
代码1是以nums[i]结尾;这个还是最容易理解和实现的!
2.二分法:最长子序列的结尾元素实时更新,因为结尾元素越小,后面连接上的概率就越大!
二分法的写法有很多种;
重要的是将所有的情况都比较到,并且有合适的结束条件!
还要注意最后定位的位置;
判断条件也很重要
1. 动态规划:将状态表示为:以nums[i]结尾的最长子序列!
时间复杂度为O(N^2),以nums[i]为结尾,需要遍历之前所有的dp
- class Solution {
- public int lengthOfLIS(int[] nums) {
- if(nums == null || nums.length == 0) return 0;
-
- //dp数组的含义是,到当前下标,此前的最长递增子序列长度
- int len = nums.length;
- int[] dp = new int[len];
- Arrays.fill(dp,1);
- int res = 1;//到这里最短为1
- for(int i = 1;i < len;i++){
- for(int j = 0;j < i;j++){
- if(nums[i] > nums[j]){
- dp[i] = Math.max(dp[i],dp[j] + 1);
- }
- }
- res = Math.max(res,dp[i]);
- }
- return res;
- }
- }
2. 二分法进行时间复杂度的优化,O(N*logN)
- class Solution {
- public int lengthOfLIS(int[] nums) {
- if(nums == null || nums.length == 0) return 0;
- int len = nums.length;
-
- int[] temp = new int[len + 1];
- int maxLen = 1;
- temp[maxLen] = nums[0];
- for(int k = 1;k < nums.length;k++){
- if(nums[k] > temp[maxLen]){
- temp[++maxLen] = nums[k];
- }
- //可能是小于或等于
- else{
- //二分法更新数组temp;二分法写法有很多种,主要包括所有情况即可
- int i = 1,j = maxLen;
- while(i < j){
- int mid = (i + j) / 2;
- if(temp[mid] < nums[k]){
- i = mid + 1;
- }else{
- j = mid;
- }
- }
- temp[i] = nums[k];
- }
- }
- return maxLen;
- }
- }