问题
给定一个未经排序的整数数组,找到最长且连续递增的子序列,并返回该序列的长度
连续递增的子序列可以由两个下标 l
和 r
(l < r)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], …, nums[r - 1], nums[r]] 就是连续递增子序列
示例 1:
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
示例 2:
输入:nums = [2,2,2,2,2]
输出:1
解释:最长连续递增序列是 [2], 长度为1
动态规划
动规五部曲分析如下:
确定dp数组以及下标的含义
**dp[i]**
:以下标**i**
为结尾的数组的连续递增的子序列长度为**dp[i]**
- 注意这里的定义,一定是以下标
i
为结尾,并不是说一定以下标0
为起始位置
确定递推公式
- 如果
nums[i + 1] > nums[i]
,那么以i+1
为结尾的数组的连续递增的子序列长度一定等于以i
为结尾的数组的连续递增的子序列长度 + 1 dp[i + 1] = dp[i] + 1;
- 因为本题要求连续递增子序列,所以就必要比较
nums[i + 1]
与nums[i]
,而不用去比较nums[j]
与nums[i]
(j是在0到i之间遍历)
- 如果
dp数组如何初始化
- 以下标
i
为结尾的数组的连续递增的子序列长度最少也应该是1
,即就是nums[i]
这一个元素
- 以下标
确定遍历顺序
- 从递推公式上可以看出,
dp[i + 1]
依赖dp[i]
,所以一定是从前向后遍历for (int i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] > nums[i]) { // 连续记录
dp[i + 1] = dp[i] + 1; // 递推公式
}
}
- 从递推公式上可以看出,
举例推导dp数组
- 已输入
nums = [1,3,5,4,7]
为例,dp数组状态如下:
- 已输入
注意这里要取dp[i]里的最大值,所以dp[2]才是结果!
class Solution {
public int findLengthOfLCIS(int[] nums) {
if (nums.length <= 1)
return nums.length;
int result = 1;
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] > nums[i]) { // 连续记录
dp[i + 1] = dp[i] + 1;
}
if (dp[i + 1] > result)
result = dp[i + 1];
}
return result;
}
}
- 时间复杂度:O(n)
-
贪心
这道题目也可以用贪心来做,也就是遇到
nums[i + 1] > nums[i]
的情况,count++
,否则count
为1
,记录count的最大值就可以了class Solution {
public int findLengthOfLCIS(int[] nums) {
if (nums.length <= 1)
return nums.length;
int result = 1; // 连续子序列最少也是1
int count = 1;
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] > nums[i]) { // 连续记录
count++;
} else { // 不连续,count从头开始
count = 1;
}
if (count > result)
result = count;
}
return result;
}
}
时间复杂度:O(n)
- 空间复杂度:O(1)