C++ day52 最长递增子序列 最长连续递增子序列 最长重复子数组

news/2024/7/7 22:20:40

题目1:300 最长递增子序列

题目链接:最长递增子序列

对题目的理解

找出整数数组中最长严格递增子序列的长度

动态规划

动规五部曲

1)dp数组及下标i的含义

dp[i]:以nums[i]为结尾的最长递增子序列的长度

递增比较的时候,如果比较 nums[j] 和 nums[i] 的大小,那么两个递增子序列一定分别以nums[j]为结尾 和 nums[i]为结尾

2)递推公式

3)dp数组初始化

根据dp数组定义,dp[i]至少长度是1,最少包含nums[i]  ,dp[i]的最大值不一定是在dp[nums.size()-1],可能出现在各个位置,因此需要遍历一遍

4)遍历顺序

求递增子序列,dp[i]依赖于前面的元素与当前数值进行比较的结果更新dp[i]的值,i从小到大遍历

for(i=1;i<nums.size();i++)  注意i从1开始,因为dp[0]代表以第一个元素结尾,最长递增子序列的长度就是1

for(j=0;j<i;j++)//j用于遍历从0到j的所有元素,j从小到大遍历,从大到小遍历均可,只要把0~i内的元素全部遍历了就行

5)打印dp数组

代码

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        //定义并初始化dp数组
        vector<int> dp(nums.size(),1);
        int result = 1;
        //递推
        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]);
            }
            result = max(result,dp[i]);//以每一个元素结尾的长度都遍历一遍,求长度的最大值
        }
        return result;
    }
};
  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n)

题目2:674 最长连续递增序列

题目链接:最长连续递增序列

对题目的理解

整数数组未经排序,找到数组中最长且连续递增的子序列,返回该序列的长度

动态规划

动规五部曲

1)dp数组及下标i的含义

dp[i]:以i结尾的最长连续递增子序列的长度,注意这里只是说了以i结尾,不一定以0开始哟,注意本题的最大长度不一定是在dp[nums.szie()-1],可能出现在各个位置,所以需要遍历一遍求最大值

2)递推公式

不连续递增子序列的跟前0-i 个状态有关,连续递增的子序列只跟前一个状态有关

3)dp数组初始化

至少有1个元素,长度是1 ,dp[i]=1

4)遍历顺序

根据递推公式,i依赖于i-1,所以,从前往后遍历

for(i=1;i<nums.size();i++), 注意i从1开始

5)打印dp数组

代码

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        //定义并初始化dp数组
        vector<int> dp(nums.size(),1);
        int result = 1;
        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;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

贪心算法

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        int count=1;
        int result = 1;
        for(int i=1;i<nums.size();i++){
            if(nums[i]>nums[i-1]) count++;//连续递增,count++
            else count = 1;//不连续递增,count从1开始计算
            result = max(result,count);
        }
        return result;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

题目3:718 最长重复子数组

题目链接:最长重复子数组

对题目的理解

返回两个整数数组中公共的且长度最长的子数组长度(子数组就是连续子序列)

动态规划

动规五部曲

1)dp数组及下标i的含义

使用二维dp数组表示两个数组的所有比较情况

dp[i][j]:以i-1为结尾的nums1和以j-1为结尾的nums2最长重复子数组的长度

注意:本题的最大长度不一定在dp[nums1.size()-1][nums2.size()-1],可能出现在各个位置,所以需要再遍历一遍,求最大值

2)递推公式

根据递推公式的定义,dp[i][j]的状态只能由dp[i-1][j-1]推导出来,if(nums1[i-1]==nums2[j-1]) dp[i][j]=dp[i-1][j-1]+1  两个数组同时回退所以只能是dp[i-1][j-1]+1,不能是dp[i][j-1]也不能是dp[i-1][j]

3)dp数组初始化

根据dp数组定义(以i-1结尾,以j-1结尾),dp[i][0]无意义状态  0-1无意义;同理,dp[0][j]无意义状态  0-1无意义,为了方便递推公式,将二者初始化为0,最长子数组长度应该从0往上加

其他的下标的dp值初始化为任意值均可(因为计算递推公式之后会被覆盖),为了代码简洁,将dp全初始化为0

4)遍历顺序

先遍历两个数组中的哪一个都可以

for(i=1;i<=nums1.size();i++){

for(j=1;j<=nums2.size();j++)}

注意从1开始遍历(根据递推公式),且条件是小于等于,因为dp数组的定义是[i][j]代表以i-1,j-1为结尾,只有等于,才能遍历到数组中的最后一个元素,nums1.size()-1,nums2.size()-1

题目要求长度最长的子数组的长度。所以在遍历的时候顺便把dp[i][j]的最大值记录下来。

5)打印dp数组

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        //定义并从初始化dp数组
        vector<vector<int>> dp(nums1.size()+1,vector<int>(nums2.size()+1));
        for(int i=0;i<nums1.size();i++){
            dp[i][0]=0;
        }
        for(int j=0;j<nums2.size();j++){
            dp[0][j]=0;
        }
        int result=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;
                result = max(result,dp[i][j]);
            }
        }
        return result;        
    }
};

初始化简便一些

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        //定义并从初始化dp数组
        vector<vector<int>> dp(nums1.size()+1,vector<int>(nums2.size()+1,0));
        int result=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;
                result = max(result,dp[i][j]);
            }
        }
        return result;        
    }
};
  • 时间复杂度:O(n × m),n 为A长度,m为B长度
  • 空间复杂度:O(n × m)

     若将dp[i][j]数组定义为nums1以i结尾和nums2以j结尾,那么 第一行和第一列毕竟要进行初始化,如果nums1[i] 与 nums2[0] 相同的话,对应的 dp[i][0]就要初始为1, 因为此时最长重复子数组为1。 nums2[j] 与 nums1[0]相同的话,也是同样要把dp[0][j]初始化为1,如下图

代码

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        //定义并从初始化dp数组
        vector<vector<int>> dp(nums1.size(),vector<int>(nums2.size(),0));
        for(int i=0;i<nums1.size();i++) if(nums1[i]==nums2[0]) dp[i][0]=1;
        for(int j=0;j<nums2.size();j++) if(nums2[j]==nums1[0]) dp[0][j]=1;
        int result = 0;
        for(int i=1;i<nums1.size();i++){
            for(int j=1;j<nums2.size();j++){
                if(nums1[i]==nums2[j])  dp[i][j]=dp[i-1][j-1]+1;
                result = max(result,dp[i][j]);
            }
        } 
        return result;
    }
};

上述代码会出现如下的错误

错误的原因是即使是上面的初始化更新了dp数组,dp数组中是1,但是最终返回了result,而result又是在for循环中,两个for循环都是从1开始记录,所以整个for循环并不包括初始化的那一列,那一行进行比较,所以最终返回的结果是0

将代码更改为如下:i=0与j=0,初始化的这一行和一列还是要在for循环中进行比较的

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        //定义并从初始化dp数组
        vector<vector<int>> dp(nums1.size(),vector<int>(nums2.size(),0));
        for(int i=0;i<nums1.size();i++) if(nums1[i]==nums2[0]) dp[i][0]=1;
        for(int j=0;j<nums2.size();j++) if(nums2[j]==nums1[0]) dp[0][j]=1;
        int result = 0;
        for(int i=0;i<nums1.size();i++){
            for(int j=0;j<nums2.size();j++){
                if(nums1[i]==nums2[j] && i>0 && j>0)  dp[i][j]=dp[i-1][j-1]+1;
                result = max(result,dp[i][j]);
            }
        } 
        return result;
    }
};

http://lihuaxi.xjx100.cn/news/1869664.html

相关文章

.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection(未完待续)

文章目录 前言什么是依赖注入C# 使用依赖注入框架介绍 Microsoft.Extensions.DependencyInjectionNuget安装简单单例使用打印结果 暂时结束 前言 依赖注入是一个非常重要的编程思想&#xff0c;就和面向过程和面向对象一样&#xff0c;IOC和控制反转是一种解耦的编程思想。 什…

Java八股文面试全套真题【含答案】- AJAX Axios篇

AJAX 是什么&#xff1f;它的全称是什么&#xff1f; 答案&#xff1a;AJAX 是 Asynchronous JavaScript and XML&#xff08;异步 JavaScript 和 XML&#xff09;的缩写。它是一种用于在后台与服务器进行数据交换的技术&#xff0c;实现异步加载数据而无需刷新整个页面。AJAX …

【100天精通Python】Day75:Python机器学习-第一个机器学习小项目_鸾尾花分类项目(上)

目录 1 机器学习中的Helloworld _鸾尾花分类项目 2 导入项目所需类库和鸾尾花数据集 2.1 导入类库 2.2 scikit-learn 库介绍 &#xff08;1&#xff09;主要特点&#xff1a; &#xff08;2&#xff09;常见的子模块&#xff1a; 3 导入鸾尾花数据集 3.1 概述数据 3.…

记录 | linux下互换键盘的Ctrl和CapsLock键

互换ctrl和CapsLK setxkbmap -option "ctrl:swapcaps"打开设置文件&#xff1a; sudo vim /etc/default/keyboard将其中的XKBOPTIONS中添加ctrl:swapcaps即可&#xff0c;如下所示&#xff1a; # KEYBOARD CONFIGURATION FILE# Consult the keyboard(5) manual pa…

WordPiece词表的创建

文章目录 一、简单介绍二、步骤流程2.1 预处理2.2 计数2.3 分割2.4 添加subword 三、代码实现 本篇内容主要介绍如何根据提供的文本内容创建 WordPiece vocabulary&#xff0c;代码来自谷歌&#xff1b; 一、简单介绍 wordpiece的目的是&#xff1a;通过考虑单词内部构造&…

Hadoop学习笔记(HDP)-Part.18 安装Flink

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

【3】密评-物理和环境安全测评

0x01 依据 GB/T 39786 -2021《信息安全技术 信息系统密码应用基本要求》针对等保三级系统要求&#xff1a; 物理和环境层面&#xff1a; a&#xff09;宜采用密码技术进行物理访问身份鉴别,保证重要区域进入人员身份的真实性&#xff1b; b&#xff09;宜采用密码技术保证电子门…

智能优化算法应用:基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.学生心理学算法4.实验参数设定5.算法结果…