300. 最长递增子序列
给你一个整数数组 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 。
思路
思考一下递推关系从哪里来?任意一个元素是否可以加入某个最长递增子序列,有两个条件:
- 递增:它一定比前方某个递增子序列的尾部元素大
a[i]>a[j], j in [0, i-1]
- 最长:它本身不属于更长的递增子序列
max(dp[i], dp[j]+1)
根据以上条件可以构造递归步骤如下:
- dp数组及其下标含义:以
nums[i]
为结尾的最长子序列长度为dp[i]
- 递推公式:根据上述条件分析,位置
i
的最长递增子序列,等于[0, i-1]
各个位置的最长递增子序列 + 1 的最大值。即:if(nums[i] > nums[j]) dp[i] = max(dp[i], dp[j]+1);
- 数组初始化:每个元素的起始子序列长度都为1,
dp[i] = 1;
- 遍历顺序:子序列必然是从前向后推导
- 举例推导:输入:[0,1,0,3,2],dp数组的变化如下:
代码实现
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int>dp(nums.size(), 1);
int result = 0;
for(int i=1; i<nums.size(); i++){
for(int j=0; j<i; j++){
if(nums[i]>nums[j]){
dp[i] = max(dp[i], dp[j]+1);
}
}
if(dp[i]>result) result = dp[i];
}
return result;
}
};
674. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 ** 连续递增的子序列** ,并返回该序列的长度。
连续递增的子序列 可以由两个下标 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 隔开。
思路
本题相较于上题额外增加了一个 连续 的条件,其实更简单了,因为不用再去跟[0, i-1]
的每一个元素进行比较,只需要跟nums[i-1]
对比,更大更长就加入,否则重新开始
- dp数组及其下标含义:以元素
i
结尾的最长连续递增子序列长度为dp[i]
- 递推公式:简化为单一比较
if(nums[i]>nums[i-1]) dp[i]=dp[i-1]+1;
- 数组初始化:同理每个元素的初始子序列为1
- 遍历顺序:同理从前向后查找子序列
- 举例推导:已输入nums = [1,3,5,4,7]为例,dp数组状态如下:
代码实现
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
vector<int> dp(nums.size(), 1);
int result = 1;
for(int i=1; i<nums.size(); i++){
if(nums[i]>nums[i-1]){
dp[i] = dp[i-1]+1;
}
if(dp[i]>result) result = dp[i];
}
return result;
}
};
注意
i
要从1
开始查找,因为它的dp结果取决于前方元素的子序列长度,dp[0-1]
会发生越界错误,上一题也翻了相同的错误,只不过用的是<i
而不是i--
因此没有报错。
718. 最长重复子数组
给两个整数数组 nums1
和 nums2
,返回 *两个数组中 公共的 、长度最长的子数组的长度 * 。
示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] 输出:3 解释:长度最长的公共子数组是 [3,2,1] 。
思路
对于两个数组的最长重复子序列,就需要用到一个二维数组记录两者的长度,
- dp数组及其下标含义:以下标
i - 1
为结尾的A,和以下标j - 1
为结尾的B,最长重复子数组长度为dp[i][j]
。 - 递推公式:`dp[i][j] = dp[i-1][j-1]+1
- 数组初始化:已知
dp[1][1] = dp[0][0] + 1
,推导出dp[0][0] = 0
- 遍历顺序:两层循环从左到右遍历A和B
- 举例推导:A: [1,2,3,2,1],B: [3,2,1,4,7]为例:
代码实现
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
vector<vector<int>>dp(nums1.size()+1, vector<int>(nums2.size()+1, 0));
int result = 0;
for(int i=1; i<=nums1.size(); i++){
for(int j=1; j<=nums2.size(); j++){
if(nums1[i-1] == nums2[j-1]){
dp[i][j] = dp[i - 1][j - 1] + 1;
}
if(dp[i][j]>result) result = dp[i][j];
}
}
return result;
}
};