【Day37 LeetCode】动态规划DP Ⅹ 子序列问题

一、动态规划DP Ⅹ 子序列问题

1、最长递增子序列 300

这题动态规划比较容易想到,dp[i]就是表示以nums[i]为结尾的数组最长递增子序列的长度,递推公式就是找到比当前值小的数(保证连续)的dp值+1,时间复杂度是O(n^2)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        // dp[i]表示以nums[i]的数组最长递增子序列的长度
        vector<int> dp(n, 1); 
        for(int i=1; i<n; ++i)
            for(int j=i-1; j>=0; --j)
                if(nums[i] > nums[j])
                    dp[i] = max(dp[i], dp[j] + 1);
        return *max_element(dp.begin(), dp.end());
    }
};

这题在时间复杂度上还有优化的点,可以看到在二重循环中,即使我们已经找到比当前值小的数a后仍需遍历完,因为之后可能还会有比当前值小的数b,且可能是最长递增子序列,因为以a结尾的最长递增子数组长度可能比以b结尾的短。而假设我们知道之前的遍历情况,记录每个递增子数组的结尾元素,贪心的想,我们只需要记录同一长度的递增子数组最小的结尾元素即可。
所以,我们可以修改dp数组的含义,dp[i]表示长度为i递增子数组的最小结尾元素。并且,在此定义下,dp数组一定是单调递增的,可以由反证法得出。
知道这个之后,我们在第二重循环中就不需要遍历所有,采用二分查找到比当前元素小的值即可。可以将时间复杂度降到O(nlogn)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        // 表示长度为i的递增子序列的最小尾数
        vector<int> dp(n + 1, INT_MIN); 
        int Len = 0;  // 当前最长递增子序列长度
        for(int i=0; i<n; ++i){
            if(nums[i] > dp[Len]){
                dp[++Len] = nums[i];
            }else if(nums[i] < dp[Len]){
                // 开始二分查找
                int left = 1, right = Len;
                while(left <= right){
                    int mid = (right - left) / 2 + left;
                    if(dp[mid] < nums[i])
                        left = mid + 1;
                    else
                        right = mid - 1;
                }
                dp[left] = nums[i];
            }
        }
        return Len;
    }
};

2、最长连续递增序列 674

这题要求子序列连续,就很简单了,一旦遇到破坏连续子序列的单调性的值,则重新开始,秒杀,代码如下:

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n, 1);
        for(int i=1; i<n; ++i)
            if(nums[i] > nums[i-1])
                dp[i] = dp[i-1] + 1;
        return *max_element(dp.begin(), dp.end());
    }
};

优化空间复杂度

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        int ans = 1, Len = 1;
        for(int i=1; i<nums.size(); ++i){
            Len = (nums[i] > nums[i-1] ? Len + 1 : 1);
            ans = max(ans, Len);
        }
        return ans;
    }
};

3、最长重复子数组 718

需要在两个数组内寻找到最长重复子数组,这个子数组是连续的。我们采用动态规划的思想来解决这个问题,dp数组是二维的,dp[i][j]表示以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度。递推关系是 如果A[i]==B[j],则 d p [ i + 1 ] [ j + 1 ] = d [ i ] [ j ] + 1 dp[i+1][j+1] = d[i][j] + 1 dp[i+1][j+1]=d[i][j]+1,这点毋庸置疑;如果A[i]!=B[j]时,由于要求子数组是连续的,所以此时 d p [ i + 1 ] [ j + 1 ] = 0 dp[i+1][j+1] = 0 dp[i+1][j+1]=0。由于我们需要找到最长重复子数组,并非一定是以某某为结尾的,所以需要取每个的dp值进行比较,取最大值。

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        int ans = 0;
        for(int i=0; i<m; ++i){
            for(int j=0; j<n; ++j){
                if(nums1[i]==nums2[j])
                    dp[i+1][j+1] = dp[i][j] + 1;
                ans = max(ans, dp[i+1][j+1]);
            }
        }
        return ans;
    }
};

由递推公式可以发现,当前dp值只与其左上角的dp值有关,则二维数组空间可以进一步优化成一维数组,代码如下,注意j的递归顺序发生了变化,变成了逆向遍历:

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        vector<int>dp(n + 1);
        int ans = 0;
        for(int i=0; i<m; ++i){
            for(int j=n-1; j>=0; --j){
                dp[j+1] = (nums1[i]==nums2[j] ? dp[j] + 1 : 0);
                ans = max(ans, dp[j+1]);
            }
        }
        return ans;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/967768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

知识图谱_protege的安装

目录 1.下载protege 2.安装可视化工具Graphviz 3.配置 参考【知识图谱】3.Protege下载安装-CSDN博客 1.下载protege 我在官网下载不了所以我就没有在官网下载 项目首页 - Protege-5.5.0Windows版本快速下载指南:Protege是一个广受欢迎的、强大的知识建模工具&#xff0c;用…

从BERT到ChatGPT:大模型训练中的存储系统挑战与技术发展——论文泛读

计算机研究与发展 2024 Paper 论文阅读笔记整理 问题 以ChatGPT为代表的大模型在文字生成、语义理解等任务上表现卓越&#xff0c;但大模型的参数量在3年内增长数万倍&#xff0c;且仍呈现增长的趋势。大模型训练面临存储挑战&#xff0c;存储需求大&#xff0c;且具有独特的…

船舶维保管理系统

一、项目介绍 381.基于SpringBoot的船舶维保管理系统&#xff0c;系统包含四种角色&#xff1a;管理员、船家、维保人员、维保公司,系统分为前台和后台两大模块&#xff0c;主要功能如下。 船家&#xff1a; - 个人中心&#xff1a;管理个人信息。 - 公告管理&#xff1a;查看…

【详细版】DETR系列之Deformable DETR(2021 ICLR)

论文标题Deformable DETR: Deformable Transformers for End-to-End Object Detection论文作者Xizhou Zhu, Weijie Su, Lewei Lu, Bin Li, Xiaogang Wang, Jifeng Dai发表日期2021年03月01日GB引用> Xizhou Zhu, Weijie Su, Lewei Lu, et al. Deformable DETR: Deformable T…

从云原生到 AI 原生,谈谈我经历的网关发展历程和趋势

作者&#xff1a;谢吉宝&#xff08;唐三&#xff09; 编者按&#xff1a; 云原生 API 网关系列教程即将推出&#xff0c;欢迎文末查看教程内容。本文整理自阿里云智能集团资深技术专家&#xff0c;云原生产品线中间件负责人谢吉宝&#xff08;唐三&#xff09; 在云栖大会的精…

基于机器学习时序库pmdarima实现时序预测

目录 一、Pmdarima实现单变量序列预测1.1 核心功能与特性1.2 技术优势对比1.3 python案例1.3.1 时间序列交叉验证1.3.1.1 滚动交叉验证1.3.1.2 滑窗交叉验证 时间序列相关参考文章&#xff1a; 时间序列预测算法—ARIMA 基于VARMAX模型的多变量时序数据预测 基于机器学习时序库…

【文本处理】如何在批量WORD和txt文本提取手机号码,固话号码,提取邮箱,删除中文,删除英文,提取车牌号等等一些文本提取固定格式的操作,基于WPF的解决方案

企业的应用场景 数据清洗&#xff1a;在进行数据导入或分析之前&#xff0c;往往需要对大量文本数据进行预处理&#xff0c;比如去除文本中的无关字符&#xff08;中文、英文&#xff09;&#xff0c;只保留需要的联系信息&#xff08;手机号码、固话号码、邮箱&#xff09;。…

小游戏源码开发之可跨app软件对接是如何设计和开发的

专业小游戏开发的团队往往会面临跨领域和不同平台客户需要追加同一款游戏的需求&#xff0c;所以就要设计和开发一款可任意对接不同 App 软件的小游戏&#xff0c;那么针对这类需求小游戏开发团队早已有了成熟的解决方案&#xff0c;针对设计和开发可跨平台游戏对接大概流程简单…

C# Winform 使用委托实现C++中回调函数的功能

C# Winform 使用委托实现C中回调函数的功能 在项目中遇到了使用C#调用C封装的接口&#xff0c;其中C接口有一个回调函数的参数。参考对比后&#xff0c;在C#中是使用委托(delegate)来实现类似的功能。 下面使用一个示例来介绍具体的使用方式&#xff1a; 第一步&#xff1a;…

从基础到人脸识别与目标检测

前言 从本文开始&#xff0c;我们将开始学习ROS机器视觉处理&#xff0c;刚开始先学习一部分外围的知识&#xff0c;为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。我采用的笔记本是联想拯救者游戏本&#xff0c;系统采用Ubuntu20.04&#xff0c;ROS采用noetic。 颜…

未来替代手机的产品,而非手机的本身

替代手机的产品包括以下几种&#xff1a; 可穿戴设备&#xff1a;智能手表、智能眼镜等可穿戴设备可以提供类似手机的功能&#xff0c;如通话、信息推送、浏览网页等。 虚拟现实&#xff08;VR&#xff09;技术&#xff1a;通过佩戴VR头显&#xff0c;用户可以进行语音通话、发…

QTreeView和QTableView单元格添加超链接

QTreeView和QTableView单元格添加超链接的方法类似,本文仅以QTreeView为例。 在QTableView仿Excel表头排序和筛选中已经实现了超链接的添加,但是需要借助delegate,这里介绍一种更简单的方式,无需借助delegate。 一.效果 二.实现 QHTreeView.h #ifndef QHTREEVIEW_H #def…

正则引入store中的modules文件

正则引入store中的modules文件 // index.js import { createStore } from vuex;const modulesFiles require.context(./modules, true, /\.ts|js$/); const modules modulesFiles.keys().reduce((modules1, modulePath) > {const moduleName modulePath.replace(/^\.\/(.…

如何保证Redis和MySQL数据的一致性刨析

1、常见的缓存更新策略&#xff1a; 定义&#xff1a;主要用来进行redis和mysql的数据同步更新的一些策略 内存淘汰&#xff1a;等触发淘汰机制后&#xff0c;刚好淘汰到了用户查询的数据&#xff0c;此时是null&#xff0c;会进行查询数据库并写入到缓存中&#xff0c;此时…

产品详情页中 品牌官网详情 对应后端的字段是 detail

文章目录 1、在这个Vue代码中&#xff0c;品牌官网详情 对应后端的字段是 detail2、品牌官网详情 功能相关的代码片段3、export const productSave (data: any) >4、ProductController5、ProductDto 类6、ProductApiService 1、在这个Vue代码中&#xff0c;品牌官网详情 对…

使用C语言实现MySQL数据库的增删改查操作指南

使用C语言与MySQL数据库进行交互,通常涉及使用MySQL提供的C API库。这套API允许开发者在C/C++程序中执行SQL查询,从而实现数据库的增删改查操作。下面,我将详细介绍如何在C语言中实现这些基本操作。 准备工作 安装MySQL开发库:确保你的系统上安装了MySQL服务器以及MySQL开发…

【蓝桥杯嵌入式】2_LED

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 1、电路图 74HC573是八位锁存器&#xff0c;当控制端LE脚为高电平时&#xff0c;芯片“导通”&#xff0c;LE为低电平时芯片“截止”即将输出状态“锁存”…

计算机视觉常用数据集Cityscapes的介绍、下载、转为YOLO格式进行训练

我在寻找Cityscapes数据集的时候花了一番功夫&#xff0c;因为官网下载需要用公司或学校邮箱邮箱注册账号&#xff0c;等待审核通过后才能进行下载数据集。并且一开始我也并不了解Cityscapes的格式和内容是什么样的&#xff0c;现在我弄明白后写下这篇文章&#xff0c;用于记录…

MariaDB MaxScale实现mysql8主从同步读写分离

一、MaxScale基本介绍 MaxScale是maridb开发的一个mysql数据中间件&#xff0c;其配置简单&#xff0c;能够实现读写分离&#xff0c;并且可以根据主从状态实现写库的自动切换&#xff0c;对多个从服务器能实现负载均衡。 二、MaxScale实验环境 中间件192.168.121.51MaxScale…

Python设计模式 - 原型模式

定义 原型模式是一种创建型设计模式&#xff0c;它可以通过复制现有对象来创建新对象&#xff0c;而不是直接实例化新的对象。 结构 抽象原型&#xff08;Prototype&#xff09;&#xff1a;声明 clone() 方法&#xff0c;以便派生类实现克隆自身的能力。具体原型&#xff08…