- 题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
处。
- 示例
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
- 算法
dp[i]表示以nums[i]点结尾的最长递增子序列的长度
nums[i]之前的所有比nums[i]小的点都可以是nums[i]之前的点
dp[i] = max(dp[i], dp[j] + 1)
- 代码
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int res = 1;
for (int i = 0; i < n; i++) {
// 自己组成子序列
dp[i] = 1;
for (int j = 0; j < i; j++) {
// 前面有人可以和自己组成子序列
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], 1 + dp[j]);
res = Math.max(res, dp[i]);
}
}
}
return res;
}
- 算法
dp[i]表示长度为i的递增子序列的结尾元素的最小值
每遇到一个nums[i],就看他能接到那些长度的子序列后面,而最后一个满足dp[x]>nums[i]时,dp[x++] = nums[j]
- 代码
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n+1];
int len = 1;
dp[1] = nums[0];
for (int i = 1; i < n; i++) {
int left = 1;
int right = len;
// 寻找每一个点可以插的点
while (left <= right) {
int mid = left + (right - left) / 2;
// 满足次条件说明可以插到dp[mid]后边组成子序列,我们要找第一个不能差的dp[left]
// 那么,长度为left的子序列的结尾元素的最小值,就是nums[i]
if (dp[mid] < nums[i]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
dp[left] = nums[i];
// 如果right没动,说明都可插,len要增加
if (right == len) {
len++;
}
}
return len;
}