代码随想录算法训练营Day-43 动态规划10 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

300.最长递增子序列

动规五部曲

dp数组含义🌟🌟🌟: 以numsi为结尾的递增子序列最大长度

注:**为什么要加上"以numsi为结尾"这个条件?**因为这样就可以在更新dp数组的时候,通过i,获取到numsi的值,而递推dp数组需要numsi的值进行比较,只有当numsj<numsi时,才进行递推更新。

**递推公式:**j从0到i-1,搜寻每一个numsj小于numsi的情况,一旦发现该情况,就更新当前的dpi为"当前dpi"和"满足numsj<numsi的dpj+1"中的最大值。

**初始化:**全部初始化为1,因为子序列长度最小为1,1就是初始状态。

遍历顺序:

外层遍历:dpi依赖于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对应值即可,如果numsi>numsi-1,说明**以numsi结尾的连续递增子序列最大长度比以numsi-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记录以每个numsi结尾的连续递增子序列最大长度,保证其始终为最大的那个。


718. 最长重复子数组

动规五部曲

dp数组含义🌟🌟🌟: 以nums1i-1和nums2j-1为公共结尾的连续重复子序列最大长度

递推公式: 遍历0~nums1.size()和0~nums2.size(),一旦发现nums1i-1==nums2j-1 ,就知道当前的dpij是在左上角的状态基础上加一,即dpij = dpi-1j-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;
    }
};

相关推荐
Pniubi1 小时前
关于算法用现成数据结构和手撕
数据结构
唐墨1232 小时前
linux kernel 比较数据大小的宏定义
linux·算法
拂拉氏3 小时前
【知识讲解-题目讲解】 统计满足K约束的子字符串数量2 (滑动窗口+前缀和+二分查找+分析)
算法·前缀和·二分查找·滑动窗口
通信小呆呆7 小时前
电子战抗干扰技术:当“不被干扰”成为一种系统
算法·通信·mimo·isac
老歌老听老掉牙7 小时前
案例 7:二维 Rosenbrock 函数最小值(香蕉函数)
c++·pso
笑容掩饰我的失落7 小时前
区块链从小白到精通(八):从零实现一个标准 ERC-20 代币(完整可运行代码)
算法·区块链·php·智能合约·哈希算法
Severus_black8 小时前
【C++初阶】Stack、Queue算法题大练兵!
c语言·c++·算法·stl
2601_9679791210 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔11 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆11 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac