子数组问题——动态规划
个人主页:敲上瘾-CSDN博客
动态规划
- 基础dp:基础dp——动态规划-CSDN博客
- 多状态dp:多状态dp——动态规划-CSDN博客
目录
一、解题技巧
二、最大子数组和
三、乘积最大子数组
四、最长湍流子数组
五、单词拆分
一、解题技巧
区分子数组(子串)与子序列:
- 子数组(子串):在数列中的一段连续的元素组成的新数列,中间不可间断。
- 子序列:在数列中从左往右依次挑选出元素组成的新数列,或者说在数列中随意删除一些元素后,剩下的元素组成的新数列。
用动态规划做子数组类的题时,对于状态表示我们可以直接设:
- dp[i]为以i元素结尾的子数组的... ...
后面就根据具体的题目要求填写,可能是子数组的和或者子数组的积等等,无论如何都可以以i元素结尾的子数组为研究对象去思考问题,如果解决不了就尝试增加状态,但研究对象不要改变。如果还解决不了那么再考虑改变或增加研究对象。
二、最大子数组和
状态表示
如上技巧所述,我们直接设状态转移方程:
- dp[i]表示:以i位置结尾的子数组的最大和。
接下来只需要去尝试是否能写出正确的状态转移方程,如果能那么状态表示就是对的。
状态转移方程:
以i位置结尾的子数组我们可以分为两种:
- nums[i]单独构成一个子数组
- nums[i]和以i-1结尾的最大和子数组组合成的子数组。
那么这个以i-1结尾的最大子数组的值就是一个重复子问题,我们假设在前面已经计算过了,即dp[i-1],然后需要注意两种情况只能取一种。那么:
- dp[i] = max(nums[i]+dp[i-1],nums[i])
初始化
初始化的目的主要有两个:
- 保证填表的时候不越界。
- 保证填表的正确性。
因为这里有i-1,所以如果从0开始填表可能会越界,通常有两种解决方案:
方法一:把dp[0]初始化(即dp[0]=nums[0]),然后从dp[1]位置开始填表(即从nums[1]位置开始记录)。
方法二:开辟一个n+1的空间(n=nums.size()),让dp[0]=0(需要根据具体情况具体分析),然后从dp[1]位置开始填写,而dp[1]记录的是nums[0]的情况,也就是错开一位进行记录,所以需要注意映射关系。
这题看似方法一更简洁,但对于其他题可能需要做更复杂的边界判断。所以在做动规题时更推荐使用方法二来解决边界问题。
填表顺序
从左往右。
返回值
dp表中的最大值。
代码示例:
class Solution
{
public:int maxSubArray(vector<int>& nums){int n=nums.size(),ret=INT_MIN;vector<int> dp(n+1);for(int i=1;i<n+1;i++){dp[i]=max(nums[i-1],nums[i-1]+dp[i-1]);ret=max(ret,dp[i]);} return ret;}
};
三、乘积最大子数组
状态表示
同样的我们假设状态表示为:
dp[i]表示:以i位置结尾的子数组的最大乘积。
那么状态转移方程dp[i]=max(dp[i-1]*nums[i],nums[i]),我们想一想这样对吗?比如dp[i-1]*nums[i],nums[i]乘以一个最大积的子数组就是最大吗?
如果nums是一个负数不就变成最小乘积了吗,反之nums[i]小于0时乘以一个最小的数才能成为最大积。
所以当nums[i]小于0时我们需要知道以i-1结尾的子数组的最小积。
所以状态表示为:
- f[i]表示:以i位置结尾的子数组的最大乘积。
- g[i]表示:以i位置结尾的子数组的最小乘积。
状态转移方程
- nums[i]>=0:
- f[i] = max(f[i-1]*nums[i],nums[i])
- g[i] = min(g[i-1]*nums[i],nums[i])
- nums[i] < 0:
- f[i] = max(g[i-1]*nums[i],nums[i])
- g[i] = min(f[i-1]*nums[i],nums[i])
或:
- f[i]=max(nums[i],max(nums[i]*f[i-1],nums[i]*g[i-1]));
- g[i]=min(nums[i],min(nums[i]*f[i-1],nums[i]*g[i-1]));
初始化
与上一题相同,为防止越界我们给两个dp表都多开辟一个空间,映射关系错开一位。
然后把两个dp表都初始化为1,因为这里是乘法,如果使用默认的0值那么这个结果都是0。
注:dp[0]是我们为防止越界添加上的虚拟位置,它的值需要使得后面的填表正确。
填表顺序
从左往右,f表和g表一起填。
返回值
f表中的最大值。
代码示例:
class Solution {
public:int maxProduct(vector<int>& nums){int n=nums.size(), ret=INT_MIN;;vector<int> f(n+1,1),g(n+1,1);for(int i=1;i<=n;i++){f[i]=max(nums[i-1],max(nums[i-1]*f[i-1],nums[i-1]*g[i-1]));g[i]=min(nums[i-1],min(nums[i-1]*f[i-1],nums[i-1]*g[i-1]));ret=max(ret,f[i]);}return ret;}
};
四、最长湍流子数组
题目的核心就一句话:比较符号在子数组中的每个相邻元素对之间翻转。
然后找到满足这样的条件的最长子数组。
状态表示
假设状态表示为:
dp[i]表示:以i结尾的最长湍流子数组。
我们把数据的大小波动抽象成一条折线,如下把示例1化为折线图:
结果取该段:
也就是子数组要满足前一个元素是上升趋势那么下一个元素必须是下降,如果前一个元素是下降趋势那么下一个元素必须是上升。
我们在做状态转移方程中主要是考虑两种情况,
- nums[i]单独构成一个子数组
- nums[i]接到前一个元素结尾构成的子数组中。
第2种情况又需要分情况讨论,
- nums[i] < nums[i-1]:只有前面的子数组最终状态是呈现上升趋势时nums[i]才能接上。
- nums[i] > nums[i-1]:只有前面的子数组最终状态是呈现下降趋势时nums[i]才能接上。
- nums[i]==nums[i-1]:不能接入前面子数组。
所以我们需要把状态转移细分为两种状态:
- f[i]表示:以i结尾并且最后一个元素呈上升趋势的最长湍流子数组的长度。
- g[i]表示:以i结尾并且最后一个元素呈下降趋势的最长湍流子数组的长度。
状态转移方程
- nums[i] < nums[i-1]:
- f[i]=1
- g[i]=f[i-1]+1
- nums[i] > nums[i-1]:
- f[i]=g[i-1]+1
- g[i]=1
- nums[i]==nums[i-1]:
- f[i]=1
- g[i]=1
因为任意一个子数组,最小的长度都是1,所以可以把两个dp表都初始化为1,那么状态转移方程可简化为:
- nums[i] < nums[i-1]:g[i]+=f[i-1]
- nums[i] > nums[i-1]:f[i]+=g[i-1]
初始化
为防止越界我们给两个dp表都多开辟一个空间,映射关系错开一位。
然后把两个dp表都初始化为1。
填表顺序
从左往右,f表和g表同时填写。
返回值
f表和g表中的最大那个元素
代码示例:
class Solution {
public:int maxTurbulenceSize(vector<int>& arr){int n=arr.size(),ret=1;vector<int> f(n,1),g(n,1);for(int i=1;i<n;i++){if(arr[i]<arr[i-1]) g[i]+=f[i-1];if(arr[i]>arr[i-1]) f[i]+=g[i-1];ret=max(ret,max(f[i],g[i]));} return ret;}
};
五、单词拆分
状态表示
根据经验直接设状态表示:
- dp[i]表示:从0到i位置结尾的字符串是否能被字典中的单词表示(bool类型)。
状态转移方程
因为在填写i时以前的每个子串是否能由字典表示已经知道,储存在dp表中。那么我们只需要找到任意一个j(0<=j<i)使得dp[j]=true,并且子字符串[j+1,i]能用字典表示,那么dp[i]=true,否则dp[i]=false。
所以状态转移方程:
- dp[i] = (dp[i-1]&&s[i,i]能用字典表示) || (dp[i-2]&&s[i-1,i]能用字典表示) || ... ... ||(dp[0]&&s[1,i]能用字典表示)
注:s[i-1,i]表示字符串中i-1到i这个子串。
初始化
为了让第一个字符元素也讨论进来,我们创建n+1的dp表,并把dp[0]初始化为true。
填表顺序
从左往右
返回值
return dp[n]
代码示例:
class Solution {
public:bool wordBreak(string s, vector<string>& wordDict){int n=s.size();unordered_set<string> st(wordDict.begin(),wordDict.end());vector<bool> dp(n+1);dp[0]=true;for(int i=1;i<=n;i++){for(int j=0;j<i;j++){if(dp[j]==false) continue;if(st.count(string(s.begin()+j,s.begin()+i))){dp[i]=true;break;}}} return dp[n];}
};
好题推荐:
- 53. 最大子数组和
- 918. 环形子数组的最大和
- 152. 乘积最大子数组
- 1567. 乘积为正数的最长子数组长度
- 413. 等差数列划分
- 978. 最长湍流子数组
- 139. 单词拆分
- 467. 环绕字符串中唯一的子字符串
非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!
相关文章:

子数组问题——动态规划
个人主页:敲上瘾-CSDN博客 动态规划 基础dp:基础dp——动态规划-CSDN博客多状态dp:多状态dp——动态规划-CSDN博客 目录 一、解题技巧 二、最大子数组和 三、乘积最大子数组 四、最长湍流子数组 五、单词拆分 一、解题技巧 区分子数组&…...

linux设置pem免密登录和密码登录
其实现在chatgpt 上面很多东西问题都可以找到比较好答案了,最近换了一个服务器,记录一下。 如果设置root用户,就直接切换到cd .ssh目录下生成ssh key即可,不需要创建用户创建用户的ssh文件夹了 比如说我要让danny这个用户可以用p…...

什么是Flask
Flask是Python中一个简单、灵活和易用的Web框架,适合初学者使用。它提供了丰富的功能和扩展性,可以帮助开发者快速构建功能完善的Web应用程序。 以下是Python Flask框架的一些特点和功能: Flask 是一个使用 Python 编写的轻量级 WSGI 微 Web…...

Spark(8)配置Hadoop集群环境-使用脚本命令实现集群文件同步
一.hadoop的运行模式 二.scp命令————基本使用 三.scp命令———拓展使用 四.rsync远程同步 五.xsync脚本集群之间的同步 一.hadoop的运行模式 hadoop一共有如下三种运行方式: 1. 本地运行。数据存储在linux本地,测试偶尔用一下。我们上一节课使用…...

【cocos creator】热更新
一、介绍 试了官方的热更新功能,总结一下 主要用于安卓包热更新 参考: Cocos Creator 2.2.2 热更新简易教程 基于cocos creator2.4.x的热更笔记 二、使用软件 1、cocos creator v2.4.10 2、creator热更新插件:热更新manifest生成工具&…...

黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色教程 针对人像、静物以及户外旅拍照片,运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具,如基本参数调整、HSL(色相、饱和度、明亮度)调整、曲线工具等改变照片原本的色彩、明度、对比度等属性,将…...

部署vue+django项目(初版)
1.准备 vscode 插件Remote SSH,连接远程,打开远程中home文件夹。 镜像和容器的一些常用命令 docker images docker ps 查看所有正在运行的容器 docker ps -a docker rmi -f tk-django-app 删除镜像 docker rm xxx 删除容器 docker start xxxx …...

Redis7系列:设置开机自启
前面的文章讲了Redis和Redis Stack的安装,随着服务器的重启,导致Redis 客户端无法连接。原来的是Redis没有配置开机自启。此文记录一下如何配置开机自启。 1、修改配置文件 前面的Redis和Redis Stack的安装的文章中已经讲了redis.config的配置…...

HarmonyOS学习第18天:多媒体功能全解析
一、开篇引入 在当今数字化时代,多媒体已经深度融入我们的日常生活。无论是在工作中通过视频会议进行沟通协作,还是在学习时借助在线课程的音频讲解加深理解,亦或是在休闲时光用手机播放音乐放松身心、观看视频打发时间,多媒体功…...

在rocklinux里面批量部署安装rocklinx9
部署三台Rockylinux9服务器 实验要求 1. 自动安装ubuntu server20以上版本 2. 自动部署三台Rockylinux9服务器,最小化安装,安装基础包,并设定国内源,设静态IP 实验步骤 安装软件 # yum源必须有epel源 # dnf install -y epel-re…...

Manus:成为AI Agent领域的标杆
一、引言 官网:Manus 随着人工智能技术的飞速发展,AI Agent(智能体)作为人工智能领域的重要分支,正逐渐从概念走向现实,并在各行各业展现出巨大的应用潜力。在众多AI Agent产品中,Manus以其独…...

【Java开发指南 | 第三十四篇】IDEA没有Java Enterprise——解决方法
读者可订阅专栏:Java开发指南 |【CSDN秋说】 文章目录 1、新建Java项目2、单击项目名,并连续按两次shift键3、在搜索栏搜索"添加框架支持"4、勾选Web应用程序5、最终界面6、添加Tomcat 1、新建Java项目 2、单击项目名,并连续按两次…...

WinForm模态与非模态窗体
1、模态窗体 1)定义: 模态窗体是指当窗体显示时,用户必须先关闭该窗体,才能继续与应用程序的其他部分进行交互。 2)特点: 窗体以模态方式显示时,会阻塞主窗体的操作。用户必须处理完模态窗体上…...

静态时序分析:SDC约束命令set_ideal_network详解
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 set_ideal_network命令可以将当前设计中的一组端口或引脚标记为理想网络源(设置端口或引脚对象的ideal_network_source属性为true)&#…...

【学习方法】技术开发者的提问智慧:如何高效获得解答?
技术开发者的提问智慧:如何高效获得解答? 在技术开发过程中,每个人都会遇到无法解决的问题。此时,我们通常会向团队、社区或论坛求助。然而,为什么有些人的问题能迅速得到解答,而有些人的问题却石沉大海&a…...

C++:入门详解(关于C与C++基本差别)
目录 一.C的第一个程序 二.命名空间(namespace) 1.命名空间的定义与使用: (1)命名空间里可以定义变量,函数,结构体等多种类型 (2)命名空间调用(…...

服务器上的nginx因漏洞扫描需要升级
前言 最近客户联系说nginx存在安全漏洞 F5 Nginx 安全漏洞(CVE-2024-7347) F5Nginx是美国F5公司的一款轻量级Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like协议下发行。F5 Nginx存在安全漏洞,该漏洞源于可能允许攻击者使用特制的…...

1688商品列表商品详情API接口全面解析
1688作为中国领先的B2B电子商务平台,汇聚了海量的商品资源,为商家和采购商提供了丰富的交易机会。为了更方便地获取和利用这些商品信息,1688平台提供了商品列表API接口,允许第三方开发者通过编程方式获取平台上的商品列表数据。本…...

【爬虫】开篇词
一、网络爬虫概述 二、网络爬虫的应用场景 三、爬虫的痛点 四、需要掌握哪些技术? 在这个信息爆炸的时代,如何高效地获取和处理海量数据成为一项核心技能。无论是数据分析、商业情报、学术研究,还是人工智能训练,网络爬虫&…...

如何在SpringBoot中灵活使用异步事件?
在现代的应用开发中,事件驱动的架构越来越受到欢迎。当我们在使用SpringBoot时,了解如何实现异步事件变得尤为重要。通过事件机制,我们能够在系统中实现松耦合的组件,让不同模块之间能够有效沟通,而无需直接依赖。本文…...

S19文件格式详解:汽车ECU软件升级中的核心镜像格式
文章目录 引言一、S19文件格式的起源与概述二、S19文件的核心结构三、S19在汽车ECU升级中的应用场景四、S19与其他格式的对比五、S19文件实例解析六、工具链支持与安全考量七、未来趋势与挑战结语引言 在汽车电子控制单元(ECU)的软件升级过程中,S19文件(也称为Motorola S-…...

git安装(windows)+vscode配置
安装git for windows在使用 Git 之前,建议设置全局的用户名称和电子邮件地址,这样每次提交代码时就可以自动关联您的身份信息。设置一次后,您无需每次都输入这些信息,Git 将自动使用您配置的全局用户信息。如果需要针对特定项目使…...

Python性能优化面试题及参考答案
目录 解释字典与列表在查找操作中的时间复杂度差异,如何利用哈希表特性提升性能? 为什么在只读场景下使用元组(tuple)比列表(list)更高效? 如何用 collections.deque 优化频繁的队列插入 / 删除操作? defaultdict 相比普通字典在哪些场景下能减少冗余代码并提升效率…...

【十四】Golang 接口
💢欢迎来到张胤尘的开源技术站 💥开源如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 接口接口定义接口初始化接口嵌套空接口存储任意类…...

ngx_openssl_create_conf
ngx_openssl_create_conf 声明在 src\event\ngx_event_openssl.c static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); 定义在 src\event\ngx_event_openssl.c static void * ngx_openssl_create_conf(ngx_cycle_t *cycle) {ngx_openssl_conf_t *oscf;oscf ngx_…...

54-WLAN 无线局域网配置方案-三层
一、网络拓扑说明 本 WLAN 网络由交换机(LSW1)、无线控制器(AC1)、无线接入点(AP1\2)以及无线客户端(STA1)组成。 用途VLANAC100AP200业务300 二、设备配置 二、设备配置 &#x…...

JVM 类加载原理之双亲委派机制(JDK8版本)
对 Java 程序的运行过程而言,类的加载依赖类加载器完成,而在 Java 默认的类加载器又分为启动类加载器、扩展类加载器和应用程序类加载器三种,但是一个类通常仅仅需要被加载一次即可,双亲委派机制即规定各个类该被何种类加载器加载…...

Mysql快速学习——《一》: Mysql的基础架构
了解mysql的基础架构, 理解大概的实现思想, 更有利与我们知之所以然, 是我们学习mysql起来思路更清晰, 效率更高. 思维导图: mysql 基础架构 mysql基础架构.png 1. 连接器 Mysql作为服务器,一个客户端的Sql连接过来就需要分配一个线程进行处理,这个线程…...

【华为OD机试真题29.9¥】(E卷,100分) - 运维日志排序(Java Python JS C++ C )
最新华为OD机试 题目描述 [运维工程师]采集到某产品线网运行一天产生的日志n条,现需根据日志时间先后顺序对日志进行排序,日志时间格式为H:M:S.N。 H表示小时(0~23)M表示分钟(0~59)S表示秒(0~59)N表示毫秒(0~999) 时间可能并没有补全,也就…...

rust编程实战:实现3d粒子渲染wasm
源码 纯js实现 fps: wasm实现 通过对比可以看出来 wasm 实现的计算比纯js刷新相对稳定。...