LeetCode 300 & 674:最长递增子序列 vs 最长连续递增子序列 ------ 联合题解 ✅
这两道题名字几乎一样,但 DP 思想和难度完全不同 。
下面我把它们 放在一张笔记里,重点对比"连续 vs 不连续"。
📌 题目列表
| 题号 | 题目 | 是否连续 |
|---|---|---|
| 300 | 最长递增子序列 | ❌ 不要求连续 |
| 674 | 最长连续递增子序列 | ✅ 必须连续 |
📖 内容概要
给定一个整数数组 nums,求 最长递增子序列的长度。
- 300:可以不连续
- 674:必须连续
✅ 动态规划
✅ 面试高频
✅ 对比强烈
💡 解题思路对比(核心)
一、状态定义(两题相同)
java
dp[i] = 以 nums[i] 结尾的递增子序列长度
二、状态转移(关键区别)
| 题目 | 状态转移 |
|---|---|
| 300 | dp[i] = max(dp[j] + 1) , j < i && nums[i] > nums[j] |
| 674 | dp[i] = dp[i-1] + 1 , nums[i] > nums[i-1] |
✅ 300 要枚举所有前面的 j
✅ 674 只看前一个
✅ 300 题:最长递增子序列(不连续)
思路
- 每个位置尝试接在所有更小的数后面
- 取最大值
AC 代码(Java)
java
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
int res = 1;
for (int i = 0; i < len; i++) {
dp[i] = 1;
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;
}
}
复杂度
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(n²) |
| 空间复杂度 | O(n) |
✅ 674 题:最长连续递增子序列
思路
- 只关心是否比前一个大
- 是 → 续上
- 否 → 重新开始
AC 代码(Java)
java
class Solution {
public int findLengthOfLCIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
int res = 1;
dp[0] = 1;
for (int i = 1; i < len; i++) {
if (nums[i] > nums[i - 1]) {
dp[i] = dp[i - 1] + 1;
} else {
dp[i] = 1;
}
res = Math.max(res, dp[i]);
}
return res;
}
}
复杂度
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(n) |
🔍 两题核心对比总结
| 对比项 | 300 | 674 |
|---|---|---|
| 是否连续 | ❌ | ✅ |
| 状态依赖 | 所有前面状态 | 仅前一个 |
| 时间复杂度 | O(n²) | O(n) |
| 难度 | 中等 | 简单 |
✅ 一句话总结
300 是"选或不选"的 DP,674 是"接或不接"的 DP。
📌 面试加分点(建议记住)
- ✅ 为什么 300 不能贪心?
- ✅ 为什么 674 不需要二维 DP?
- ✅ 什么时候可以用贪心代替 DP?
- ✅ 如何把 300 优化到 O(n log n)