目录
题目链接:300.最长递增子序列
思路
子序列是数组派生而来的,删除或者不删除元素都不影响其余元素的顺序。该定义是这道题的难点,使用动态规划来解决。
①dp数组,dp[i]表示i之前包括i的以nums[i]结尾的最长子序列的长度
②递推公式,dp[i] = max(dp[i], dp[j] +1),位置i的最长递增子序列是j从0到i-1最长子序列加1的最大值
③dp数组初始化,初始化为1,最长子序列长度最短为1
④遍历顺序,从前往后,先i后j
⑤推导dp数组
代码
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.size() == 1)
return 1;
vector<int> dp(nums.size(), 1);
int result = 0;
// j从0到i-1,有比nums[i]小的,利用递推公式更新
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. 最长连续递增序列
思路
可以使用贪心算法,也可以使用动态规划解决。
代码
贪心
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if(nums.size() == 1) return 1;
int maxlen = 1;
int curlen = 1;
for(int i = 1; i < nums.size(); i++){
if(nums[i]>nums[i-1]){
curlen++;
}
else{
curlen = 1;
}
maxlen = max(maxlen,curlen);
}
return maxlen;
}
};
动态规划
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if (nums.size() == 1)
return 1;
vector<int> dp(nums.size(), 1);
int result = 0;
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;
}
};
题目链接:718. 最长重复子数组
思路
①dp数组,dp[i][j]表示以i-1结尾的A和以j-1结尾的B最长重复子数组的长度为dp[i][j]
②递推公式,如果A[i-1] == B[j-1],则dp[i][j] = dp[i-1][j-1]+1
③dp数组初始化,按照dp数组定义dp[i][0]和dp[0][j]并无意义,但是按照题意可以将dp[0][0]初始化为0,每次相等时,长度加一
④遍历顺序,先A后B或者先B后A都可以,两层循环都从1开始从前往后
⑤推导dp数组
代码
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
int result = 0;
// 二维dp数组,大小为m*n
vector<vector<int>> dp(nums1.size() + 1,
vector<int>(nums2.size() + 1, 0));
for (int i = 1; i <= nums1.size(); i++) {
for (int j = 1; j <= nums2.size(); j++) {
// 每当前一位相等时,dp数组当前位置值加1
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
if (result < dp[i][j])
result = dp[i][j]; // 更新result
}
}
return result;
}
};
总结
①子序列问题,dp数组的定义会简单一些,目前没有股票问题那么多状态
②简单的子序列问题也可以使用贪心算法试试