300.最长递增子序列
动规五部曲
dp数组含义🌟🌟🌟: 以nums[i]为结尾的递增子序列最大长度
注:**为什么要加上"以nums[i]为结尾"这个条件?**因为这样就可以在更新dp数组的时候,通过i,获取到nums[i]的值,而递推dp数组需要nums[i]的值进行比较,只有当nums[j]<nums[i]时,才进行递推更新。
**递推公式:**j从0到i-1,搜寻每一个nums[j]小于nums[i]的情况,一旦发现该情况,就更新当前的dp[i]为"当前dp[i]"和"满足nums[j]<nums[i]的dp[j]+1"中的最大值。
**初始化:**全部初始化为1,因为子序列长度最小为1,1就是初始状态。
遍历顺序:
外层遍历:dp[i]依赖于0~i-1状态推导过来,所以只能从前向后顺序遍历,从1遍历到nums.size()-1;
内层遍历:只需要遍历完0~i-1这些索引即可,顺序倒序不重要
cpp
class Solution {
public:
int lengthOfLIS(vector<int>& nums){
if(nums.size()==1) return 1;
//dp[i]含义:以nums[i]为结尾的递增子序列最大长度
//初始化:全部初始化为1,因为至少递增子序列长度不小于1,因此1为起始状态
vector<int> dp(nums.size(),1);
//由于最终不一定以谁结尾的递增子序列最大长度最大,所以要时刻更新result为最大递增子序列长度
int result = 0;
//遍历顺序:外层遍历i,从1开始到最后,因为dp[0]一定为1,不用考虑
//内层遍历j,从0到i-1,搜寻每一个nums[j]小于nums[i]的情况,一旦发现该情况,就更新当前的dp[i],确保满足该情况的dp[j]+1不大于dp[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[j]+1, dp[i]);
}
}
//检查当前dp[i]是否超过result记录的最大长度,若超过则更新
if(dp[i]>result) result = dp[i];
}
return result;
}
};
674. 最长连续递增序列
本题和上题的区别就在于本题是"连续"数组,所以递推时只需考虑上一状态也就是i-1的nums对应值即可,如果nums[i]>nums[i-1],说明**以nums[i]结尾的连续递增子序列最大长度比以nums[i-1]结尾的长度大1,**故递推公式变为:
cpp
if(nums[i]>nums[i-1]){
dp[i] = dp[i-1]+1;
}
遍历顺序 也只需要单层遍历,因为不需要考虑所有前i种情况,只需要考虑前一个情况。
cpp
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(result<dp[i]) result = dp[i];
}
return result;
}
};
**注:**同样需要result记录以每个nums[i]结尾的连续递增子序列最大长度,保证其始终为最大的那个。
718. 最长重复子数组
动规五部曲
dp数组含义🌟🌟🌟: 以nums1[i-1]和nums2[j-1]为公共结尾的连续重复子序列最大长度
递推公式: 遍历0~nums1.size()和0~nums2.size(),一旦发现nums1[i-1]==nums2[j-1] ,就知道当前的dp[i][j]是在左上角的状态基础上加一,即dp[i][j] = dp[i-1][j-1]+1,为什么是左上角,因为i-1和j-1是新的公共结尾,所以i和j都需要回退1格。
初始化: 全部初始化为0,因为最左和最上列无意义,所以初始化为更新的初始状态0(要从0开始1个1个加长度),其余位置无所谓,因为会被覆盖,所以索性可以全初始化为0
遍历顺序:
先nums1还是nums2都可以 ,遍历顺序为顺序,因为需要前面的i-1和j-1为基础。
cpp
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
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++){
if(nums1[i-1]==nums2[j-1]) dp[i][j] = dp[i-1][j-1]+1;
}
}
int result = 0;
for(int i = 1; i <= nums1.size(); i++){
for(int j = 1; j<=nums2.size(); j++){
if(dp[i][j]>result) result = dp[i][j];
}
}
return result;
}
};