最长递增子序列
方法一:dp[i] 表示以 nums[i] 结尾的递增子序列的最大长度,复杂略高
// 时间复杂度高
public int lengthOfLIS(int[] nums) {
// dp[i] 以 nums[i] 为结尾的严格递增子序列
int[] dp = new int[nums.length];
dp[0] = 1;
int max = 1;
for (int i = 1; i < dp.length; i++) {
for (int j = i - 1; j >= 0; j--) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j]);
}
}
dp[i] += 1;
max = Math.max(dp[i], max);
}
return max;
}
方法二:如果有一个数组 tail[i] 保存了长度为 i+1 的递增子序列各种情况下最小的尾项,那么我们就有更大的几率在后面找到比 tail[i] 大的项,以增加最大子序列的长度
// 贪心 + 二分查找
public int lengthOfLISPro(int[] nums) {
// tail[i] 表示子序列长度为 i+1 时,最后一个数字
int[] tail = new int[nums.length];
tail[0] = nums[0];
int len = 1;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > tail[len - 1]) {
tail[len] = nums[i];
len++;
} else {
// 二分查找,找最后一个比 num[i] 小的 tail[j],用 num[i] 更新 tail[j + 1]
// 这就说明可以在 tail[j] 对应的数字后接上 num[i],构成长度为 j + 2 的子串,而且这个子串的末尾项即 num[i] 小于 目前的 tail[j + 1]
// 所以为了维护 tail 数组要进行替换
int low = 0, high = len - 1;
while (low <= high) {
int cen = (high - low) / 2 + low;
if (tail[cen] >= nums[i]) {
high = cen - 1;
} else {
low = cen + 1;
}
}
tail[high + 1] = nums[i];
}
}
return len;
}
这个动态规划的数组索引是答案,而以前都是数组内容作为答案
动态规划真的难顶。。。