LIS
给你一个整数数组 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
回溯三问
//记忆化搜索
class Solution {
private int[] nums, cache;
public int lengthOfLIS(int[] nums) {
this.nums = nums;
int n = nums.length;
cache = new int[n];
int res = 0;
for (int i = 0; i < n; i++) {
res = Math.max(res, dfs(i));
}
return res;
}
private int dfs(int i) {
if (cache[i] > 0) {
return cache[i];
}
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
cache[i] = Math.max(cache[i], dfs(j));
}
}
//最后需要加上nums[i],因此需要+1
return ++cache[i];
}
}
递推
//递推
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] f = new int[n];
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
f[i] = Math.max(f[i], f[j]);
}
}
res = Math.max(res, ++f[i]);
}
return res;
}
}
g[i]表示长度为i+1的IS(递增子序列)的最小值
例如,nums=[1,6,7,2,4,5,3]
nums = 1
nums = 1 6
nums = 1 6 7
nums = 1 2 7
nums = 1 2 4
nums = 1 2 4 5
nums = 1 2 3 5
class Solution {
public int lengthOfLIS(int[] nums) {
List<Integer> g = new ArrayList<>();
for (int x : nums) {
int j = lowerBound(g, x);
if (j == g.size()) {
g.add(x);
} else {
g.set(j, x);
}
}
return g.size();
}
public int lowerBound(List<Integer> g, int target) {
int left = 0, right = g.size() - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (g.get(mid) < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
}
空间优化
class Solution {
public int lengthOfLIS(int[] nums) {
int ng = 0;
for (int x : nums) {
int j = lowerBound(nums, ng - 1, x);
nums[j] = x;
if (j == ng) {
ng++;
}
}
return ng;
}
public int lowerBound(int nums[], int right, int target) {
int left = 0;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
}