代码随想录算法训练营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;
    }
};

相关推荐
show4332 分钟前
2026小程序端AI智能优化技术实践:转文字后自动纠错+润色+分段算法分析
人工智能·算法·小程序
郝学胜_神的一滴3 分钟前
C++20 高级编程 003:吃透现代基础语法与标准容器
c++
码匠许师傅7 分钟前
【C++ 面试真题】聊聊 C++ 的关联容器
开发语言·c++·面试
平生不晚29 分钟前
在 SVG 体系里画一条任意的线
前端·算法
evans在进步1 小时前
LeetCode 198:打家劫舍——Java 动态规划详解
java·leetcode·动态规划
Hhy_11071 小时前
《C++深度解构02》类和对象(上)——定义规范、内存对齐与 this 指针全解
c语言·开发语言·c++·学习·visual studio
晚风叙码1 小时前
C++哈希表实现:开放定址法和链地址法 (哈希桶)
数据结构·c++·哈希算法·散列表
imaol11 小时前
哈希表--数据结构
数据结构·散列表
逆境不可逃1 小时前
LeetCode 双题:415. 字符串相加与 143. 重排链表
算法
2601_950760792 小时前
TNF-α:自身免疫疾病治疗的核心靶点与信号通路解析
人工智能·算法·蛋白