子数组问题——动态规划
个人主页:敲上瘾-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时,了解如何实现异步事件变得尤为重要。通过事件机制,我们能够在系统中实现松耦合的组件,让不同模块之间能够有效沟通,而无需直接依赖。本文…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
