1.最长递增子序列
代码:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
vector<int> dp(nums.size(),1);
int result = 0;
// dp[i] 表示以下标i为结尾的[0,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);
}
}
result = max(result, dp[i]);
}
return result;
}
};
note:
注意:因为result初始值为0,如果没有进入循环的话,会一直保持初始,导致nums.size()==1的情况也返回了0。所以在开头就要及时把意外情况返回。
dp数组的含义:以i为结尾的在下标为[0,i]的元素组成的最长递增子序列的长度为dp[i]
递推公式:要知道子序列不必连续,因此为了方便写出递推公式,规定至少要以nums[i]作为结尾,方便去比较,从而去递推。而且,在递推的时候要去循环遍历所有的[0,i - 1]的dp数组的元素,因为我们可以在这些范围内的任意一个满足条件的子序列上增加元素。所以,dp[i]就去取这些增加元素后的子序列长度的最大值。dp[i] = max(dp[i],dp[j] + 1)
dp数组的初始化:由于在定义中要求至少以nums[i]为结尾,因此每个子序列至少包含一个元素,都初始化为1
遍历顺序:对于变量i,必须正序遍历,因为后面的元素依赖前面的元素。但是对于变量j则无所谓,只要遍历一遍取最大值就好了。
2.最长连续递增序列
代码:
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
vector<int> dp(nums.size(),1);
// dp[i] 表示以i为结尾的最长连续递增序列的长度
int result = 0;
for(int i = 1; i < nums.size(); i++){
if(nums[i] > nums[i - 1]){
dp[i] = dp[i - 1] + 1;
}
result = max(result, dp[i]);
}
return result;
}
};
note:
dp数组的含义:以i为结尾的最长连续递增序列的长度
递推公式:由于这一次是连续的,因此不需要去循环遍历i之前的dp元素了,而是在满足条件的情况下,直接dp[i] = dp[i - 1] + 1
dp数组的初始化:至少包含作为结尾的nums[i],因此都初始化为1
遍历顺序:正序遍历,后面的元素依赖于前面的元素
3.最长重复子数组
代码:
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;
// dp[i][j] 表示以nums1中以i-1为结尾 和 nums2中以j-1为结尾的 的最长重复子数组的长度
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;
}
result = max(result, dp[i][j]);
}
}
return result;
}
};
note:
注意此题是以i-1和j - 1为结尾,因此比较的时候也是比较nums1[i - 1]和nums2[j - 1]
dp数组的含义:dp[i][j] 表示以nums1中以i-1为结尾 和 nums2中以j-1为结尾的 的最长重复子数组的长度
递推公式:如果num1[i - 1] == nums2[j - 1],则dp[i][j] = dp[i - 1][ j - 1]
dp数组的初始化:dp数组的含义正好使得此数组第一行和第一列没有实际含义,只要填0不影响计算就好了。其它的元素的值则会在遍历中被覆盖,初始值为什么都可以。