最长序列
300. 最长递增子序列【中等】
- 方法一:动态规划
时间复杂度:O(n^2)
空间复杂度:O(n)
1、确定dp数组及其含义
dp[i]
表示0~i索引的最长上升子序列长度
2、确定状态转移方程
if(nums[i] > nums[j]) dp[i] = max(dp[i], dp[j]+1);
3、dp初始化
dp[i] = 1;
,只要nums有长度,至少为1
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
// dp初始化
vector<int> dp(nums.size(), 1);
int maxLen = 0;
for (int i = 1; i < nums.size(); ++i) { //以i结尾的nums的最长上升子序列
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
maxLen = max(maxLen, dp[i]);
}
return maxLen;
}
};
方法二:贪心+二分查找
时间复杂度:O(nlogn)
空间复杂度:O(n)
674. 最长连续递增序列【简单】
思路一:动态规划
时间复杂度:O(n)
空间复杂度:O(n)
1、确定dp数组及其下标含义
dp[i]
是索引0~i时连续递增子序列长度
2、确定递推公式
if(nums[i] > nums[i-1]) dp[i] = dp[i-1] + 1;
3、dp初始化
vector<int> dp(nums.size(), 1);
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
int maxLen = 1;
vector<int> dp(nums.size() ,1);
for (int i = 1; i < nums.size(); i++) {
if (nums[i] > nums[i-1]) // 连续记录
dp[i] = dp[i-1] + 1;
maxLen = max(maxLen, dp[i]);
}
return maxLen;
}
};
- 思路二:贪心
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
int maxLen = 1;
int count = 1;
for (int i = 1; i < nums.size(); i++) {
if (nums[i] > nums[i-1]) count++;
else count = 1;
maxLen = max(maxLen, count);
}
return maxLen;
}
};
思路三:双指针
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
int maxLen = 1;
int start = 0;
for(int end = 1; end < nums.size(); ++end){
if(nums[end] <= nums[end-1]){
maxLen = max(maxLen, end - start);
start = end;
}
}
//最后一节
if(nums.size() - start > maxLen) maxLen = nums.size() - start;
return maxLen;
}
};
718. 最长重复子数组【中等】
思路:动态规划
时间复杂度:O(mn)
空间复杂度:O(mn)
1、确定dp数组及其下标含义
dp[i][j]
:以下标i-1结尾的A,j-1结尾的B,它们的最长重复子数组长度
2、确定递推公式
dp[i][j] = dp[i-1][j-1] + 1;
3、dp初始化
dp[i][0] = 0;
dp[0][j] = 0;
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
vector<vector<int>> dp (A.size() + 1, vector<int>(B.size() + 1, 0));
int maxLen = 0;
for (int i = 1; i <= A.size(); i++) {
for (int j = 1; j <= B.size(); j++) {
if (A[i - 1] == B[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
maxLen = max(maxLen, dp[i][j]);
}
}
return maxLen;
}
};
思路二:空间优化,滚动数组
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
vector<int> dp(vector<int>(B.size() + 1, 0));
int maxLen = 0;
for (int i = 1; i <= A.size(); i++) {
for (int j = B.size(); j > 0; j--) {
if (A[i - 1] == B[j - 1]) {
dp[j] = dp[j - 1] + 1;
}
else dp[j] = 0; // 注意这里不相等的时候要有赋0的操作
maxLen = max(maxLen, dp[j]);
}
}
return maxLen;
}
};
1143. 最长公共子序列【中等】
- 思路:动态规划
时间复杂度:O(mn)
空间复杂度:O(mn)
1、确定dp数组以及下标含义
dp[i][j]
:索引为0-i的text1与0-j的text2的最长公共子序列
2、确定递推公式
if(text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
if(text1[i-1] != text2[j-1]) dp[i][j] != max(dp[i-1][j], dp[i][j-1]);
3、dp初始化
vector<vector<int>> dp(text1.size(), vector<int>(text2.size(), 0));
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
vector<vector<int>> dp(text1.size()+1, vector<int>(text2.size()+1, 0));
for(int i = 1; i <= text1.size(); i++){
for(int j = 1; j <= text2.size(); j++){
if(text1[i-1] == text2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
}
else{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[text1.size()][text2.size()];
}
};