87.最长递增子序列
给你一个整数数组 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 。
示例2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
- 1 <= nums.length <= 2500
- -104 <= nums[i] <= 104
代码:
1.动态规划(时间复杂度O(n2))
class Solution {
public int lengthOfLIS(int[] nums) {
//dp[i] 表示以 nums[i] 结尾的最长递增子序列(LIS)的长度
int[] dp = new int[nums.length];
//存储最终结果,即最长递增子序列的长度
int res = 0;
//遍历数组,计算每个位置 i 的 dp[i]
for(int i = 0;i<nums.length;i++){
//初始情况下,每个元素自身构成一个长度为 1 的递增子序列
dp[i] = 1;
//如果 nums[j] < nums[i],说明 nums[i] 可以接在 nums[j] 后面形成更长的递增子序列
//更新 dp[i],取 dp[j] + 1 和当前 dp[i] 的较大值
for(int j = 0;j<i;j++)if(nums[j]<nums[i])dp[i] = Math.max(dp[i],dp[j]+1);
}
//遍历 dp 数组,找到最大的值(即最长递增子序列的长度)
for(int i = 0;i<nums.length;i++)res = Math.max(res,dp[i]);
//返回结果
return res;
}
}
2.贪心+二分查找(时间复杂度O(nlogn))
class Solution {
public int lengthOfLIS(int[] nums) {
//p[i]表示长度为i的LIS的最小末尾元素
//p[0]无意义,从p[1]开始使用
int[] p = new int[nums.length+1];
//当前LIS的最大长度
int len = 0;
for(int i = 0;i<nums.length;i++){
//在p[1..len]中查找第一个>=nums[i]的位置t
int t = lower_bound(1,len+1,nums[i],p);
//更新p[t] = nums[i],表示长度为t的LIS的最小末尾可以更小
p[t] = nums[i];
//如果t超过了当前最大长度,说明可以扩展LIS
if(t>len)len++;
}
//返回最长递增子序列的长度
return len;
}
//在 p[l..r-1] 范围内查找第一个 ≥ target 的位置
public int lower_bound(int l,int r,int target,int[] p){
while(l<r){
int mid = l+r>>1;
if(p[mid]>=target)r = mid;
else l = mid+1;
}
return l;
}
}

浙公网安备 33010602011771号