DP:子数组问题
文章目录
- 引言
- 子数组问题介绍
- 动态规划的基本概念
- 具体问题的解决方法
- 动态规划解法:
- 关于子数组问题的几个题
- 1.最大子数组和
- 2.环形子数组的最大和
- 3.乘积最大子数组
- 4.乘积为正数的最长子数组长度
- 5.等差数列划分
- 总结
引言
介绍动态规划(DP)在解决子数组问题上的重要性,以及本文的目的——通过具体问题的分析和代码示例,帮助读者理解如何用DP解决子数组问题。
子数组问题介绍
简要介绍什么是子数组问题,以及这些问题在实际应用中的重要性。例如,最大子数组和问题、最长递增子数组问题等。
动态规划的基本概念
解释动态规划的基本思想:通过将问题分解为子问题,保存子问题的解来避免重复计算,从而提高算法效率。可以简单介绍状态、状态转移方程和初始条件等基本概念。
具体问题的解决方法
最大子数组和问题(Maximum Subarray Sum)
问题描述:
给定一个整数数组,找出和最大的连续子数组,并返回其最大和。
动态规划解法:
定义状态:dp[i]表示以第i个元素结尾的最大子数组和。
状态转移方程:dp[i] = max(nums[i], dp[i-1] + nums[i])
即对于第i个元素,最大子数组和要么是自己,要么是前一个元素的最大子数组和加上自己。
初始状态:dp[0] = nums[0]
结果:max(dp),即所有dp[i]中的最大值。
关于子数组问题的几个题
1.最大子数组和
题目链接
题目:
样例输出和输入:
题目要求很简单,就是求出 最长的子数组的和,这个和有一个要求就是和最大。
算法原理:
状态表示:dp[i]表示以i位置为结尾时所有子数组的和中最大的那个。
状态转移方程:
分析:到达i位置时i位置最长的子数组的和应该等于i-1位置的最长子数组的和加上当前i位置的值,还有一种情况:单独分析,就是当前位置的数就是一个子数组,长度为1,所以,dp[i]=max(dp[i-1]+nums[i],nums[i])。
代码展示:
class Solution {
public:int maxSubArray(vector<int>& nums){int n = nums.size();vector<int> dp(n);dp[0] = nums[0];for (int i = 1;i < n;i++){dp[i] = max(dp[i - 1] + nums[i], nums[i]);}int Max = -0x3f3f3f3f;for (int i = 0;i < n;i++){Max = max(dp[i], Max);}return Max;}
};
运行结果:

2.环形子数组的最大和
题目链接
题目:
样例输出和输入:
这道题在第一道题的基础上加了一个条件,就是这是个环形数组头和尾是相连的。也让我们求子数组中和最大的那个。
算法原理:
状态表示:分析:明显这道题一个状态是表示不了的,因为这个子数组可能连续也可能不连续,由于求的最大的值,所以第一种情况:当子数组在中间时最大,还有一种情况,子数组在两边时不连续的时候最大 ,当不连续的时候 最大,也就是中间的最小。这两种状态分别为f[i]和g[i]。

状态转移方程:先分析中间最大的时候的状态,当到达i位置的时候i位置的最大的子数组的和就是前一个位置i-1的位置的最大的子数组的和加上当前i位置的值,还有一种情况就是i位置自身成一个长度为1的数组。f[i] = max(f[i - 1] + nums[i-1], nums[i-1]),g[i]也同理,g[i]为当前位置的子数组中最小的那个 子数组的和,所以i位置的子数组和的最小等于前一个位置的子数组和的最小,加上当前位置,g[i - 1] + nums[i-1]最后还要取一个min,g[i] = min(g[i - 1] + nums[i-1], nums[i-1])
代码展示:
class Solution {
public:int maxSubarraySumCircular(vector<int>& nums){int n = nums.size();vector<int> f(n + 1), g(n + 1);int sum = 0;int fmax = INT_MIN;int gmin = INT_MAX;for (int i = 1;i <= n;i++){f[i] = max(f[i - 1] + nums[i-1], nums[i-1]);fmax = max(f[i], fmax);g[i] = min(g[i - 1] + nums[i-1], nums[i-1]);gmin = min(gmin, g[i]);sum += nums[i - 1];}return sum == gmin ? fmax : max(fmax, sum - gmin);}
};
运行结果:

3.乘积最大子数组
题目链接
题目:
样例输出和输入:
这道题的题意和前两道题也大差不差,就是让我们求最大乘积的子数组的乘积。
算法原理:
状态表示:这道题还是需要两个状态,因为有负数情况,不一定是正数乘正数才是最大的,两个负数相乘也 有可能是最大的。f[i]表示以i位置为结尾的子数组中的最大乘积的那个,g[i]表示以i位置为结尾的子数组中最小的乘积的那个。
状态转移方程:首先分析f[i]这个状态,这个状态有三个子状态,第一种状态是i位置是负数时,所以负数应乘上最小的才是最大的,还有一种状态就是当前位置是正数,所以当前位置应该乘上前一个位置中最大的那个子数组的乘积。还有一个情况就是单独成为一个子数组。

max(nums[i - 1], max(f[i - 1] * nums[i - 1], g[i - 1] * nums[i - 1]))
g[i]的状态转移方程也可以用类似的方法进行分析:min(nums[i - 1], min(f[i - 1] * nums[i - 1], g[i - 1] * nums[i - 1]))
代码展示:
class Solution {
public:int maxProduct(vector<int>& nums){int n = nums.size();vector<double> f(n + 1), g(n + 1);//f是最大的,g是最小的g[0] = 1, f[0] = 1;double ret = INT_MIN;for (int i = 1;i <= n;i++){double x = nums[i - 1], y = f[i - 1] * nums[i - 1], z = g[i - 1] * nums[i - 1];f[i] = max(x, max(y, z));g[i] = min(x, min(y, z));ret = max(f[i], ret);}return ret;}
};
运行结果:

4.乘积为正数的最长子数组长度
题目链接
题目:
样例输出和输入:
这道题要求的是乘积是正数的子数组总长度最长的那个子数组的长度。
算法原理:
状态表示:由于两个负数相乘也是正数,所以状态表示的时候我们也要记录负数的状态,f[i]表示以i位置为结尾的所有子数组中乘积是正数的最长的子数组的长度,g[i]]是以i位置为结尾的子数组中乘积为负数的最长子数组的长度。
状态转移方程:需要判断i位置的值是正数还是负数,如果是负数的话就是就需要用前一个位置的负数子数组的最长的那个加一,也就是g[i-1]+1但是前i-1个有可能没有小于零的,所以这里f[i]是有可能是零的,所以这里需要判断一下i-1位置时的g[i-1]的值,当当前值大于零的时候f[i]就等于 前一个位置的f[i-1]+1,同理负数的最长子数组也可以分析出来,状态转移方程:这是大于零的两种状态的情况:g[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1,f[i] = f[i - 1] + 1小于零的两种状态的情况:f[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1,g[i] = f[i - 1] + 1。
代码展示:
class Solution {
public:int getMaxLen(vector<int>& nums) {int n = nums.size();if (n == 1){return nums[0] > 0;}vector<int> f(n), g(n);f[0] = nums[0] > 0, g[0] = nums[0] < 0;int fmax = 0;for (int i = 1;i < n;i++){if (nums[i] > 0){f[i] = f[i - 1] + 1;g[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1;fmax = max(f[i], fmax);}else if (nums[i] < 0){f[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1;g[i] = f[i - 1] + 1;fmax = max(f[i], fmax);}}return fmax;}
};
运行结果:

5.等差数列划分
题目链接
题目:
样例输出和输入:
这道题题意很简单,就是让我们求所有能构成等差数列的子数组的总和
算法原理:
等差数列性质:2a=c+ba为等差中项。
状态表示:dp[i]为以i位置为结尾的所有子数组中的等差数列的个数。
状态转移方程:先判断i位置的前两个位置是否 满足上述的等差数列的性质:如果满足则dp[i]=dp[i - 1] + 1因为满足,所以dp[i-1]位置需要算上,但是又多了一个子数组,这个子数组 就是满足的那个三个数的子数组。不满足的话,dp[i]直接就是0.
代码展示:
class Solution {
public:int numberOfArithmeticSlices(vector<int>& nums) {int n = nums.size();if (n < 3){return 0;}vector<int> dp(n);dp[0] = 0, dp[1] = 0;int count = 0;for (int i = 2;i < n;i++){dp[i] = nums[i] + nums[i - 2] == 2 * nums[i - 1] ? dp[i - 1] + 1 : 0;}for(int i=0;i<n;i++){count+=dp[i];}return count;}
};
运行结果:

总结
通过本文的介绍,我们详细探讨了动态规划在解决子数组问题中的应用,具体分析了最大子数组和问题和最长递增子数组问题。这些问题在实际生活中的数据处理、优化等场景中有着广泛的应用。动态规划通过将问题分解为子问题,保存子问题的解,避免了重复计算,从而大大提高了算法的效率。
在学习和应用动态规划的过程中,我们需要明确状态、状态转移方程和初始条件。通过练习具体问题,我们可以更深入地理解动态规划的思想和方法。无论是最大子数组和问题还是最长递增子数组问题,掌握了动态规划的基本原理后,我们可以更灵活地应对其他类似的问题。
希望这篇文章能帮助你更好地理解动态规划在子数组问题中的应用。如果你有任何问题或建议,欢迎在评论区留言,我们将尽力为你解答。祝你在学习动态规划和解决实际问题的过程中取得更多的进步!
相关文章:
DP:子数组问题
文章目录 引言子数组问题介绍动态规划的基本概念具体问题的解决方法动态规划解法:关于子数组问题的几个题1.最大子数组和2.环形子数组的最大和3.乘积最大子数组4.乘积为正数的最长子数组长度5.等差数列划分 总结 引言 介绍动态规划(DP)在解决…...
[Day 20] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
AI在醫療領域的創新應用 隨著科技的快速發展,人工智能(AI)在各行各業的應用越來越廣泛,醫療領域也不例外。AI技術在醫療中的應用不僅提高了診斷的準確性,還改善了病患的治療效果,優化了醫療資源的配置。本…...
Handling `nil` Values in `NSDictionary` in Objective-C
Handling nil Values in NSDictionary in Objective-C When working with Objective-C, particularly when dealing with data returned from a server, it’s crucial (至关重要的) to handle nil values appropriately (适当地) to prevent unexpected crashes. Here, we ex…...
【深入浅出 】——【Python 字典】——【详解】
目录 1. 什么是 Python 字典? 1.1 字典的基本概念 1.2 字典的用途 1.3 字典的优势 2. 字典的基本特点 2.1 键的唯一性 2.2 可变性 2.3 无序性 3. 如何创建字典? 3.1 使用 {} 符号 3.2 使用 dict() 工厂方法 3.3 使用 fromkeys() 方法 4. 字…...
开发RpcProvider的发布服务(NotifyService)
1.发布服务过程 目前完成了mprpc框架项目中的以上的功能。 作为rpcprovider的使用者,也就是rpc方法的发布方 main函数如下: 首先我们init调用框架的init,然后启动一个provider,然后向provider上注册服务对象方法,即us…...
Suno: AI音乐创作的新时代
名人说:一点浩然气,千里快哉风。 ——苏轼 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、什么是Suno?1、Suno2、应用场景二、如何使用Suno制作音乐?步骤1:注册并登录Suno平台步骤2:创建音乐项目步骤3:生成音乐片段三、Suno的影响很高兴你打开了…...
六西格玛项目实战:数据驱动,手机PCM率直线下降
在当前智能手机市场日益竞争激烈的背景下,消费者对手机质量的要求达到了前所未有的高度。PCM(可能指生产过程中的某种不良率或缺陷率)作为影响手机质量的关键因素,直接关联到消费者满意度和品牌形象。为了应对这一挑战,…...
数据结构递归(01)汉诺塔经典问题
说明:使用递归时,必须要遵守两个限制条件: 递归存在限制条件,满⾜这个限制条件时,递归不再继续; 每次递归调⽤之后越来越接近这个限制条件; 1 汉诺塔(Hanoi Tower)经典…...
计算机专业课面试常见问题-计算机网络篇
目录 1. 计算机网络分为哪 5 层? 2. TCP 协议简述? 3. TCP 和 UDP 的区别?->不同的应用场景? 4. 从浏览器输入网址到显示页…...
HarmonyOS ArkUi ArkWeb加载不出网页问题踩坑
使用 使用还是比较简单的,直接贴代码了 别忘了配置网络权限 Entry Component struct WebPage {State isAttachController: boolean falseState url: string State title: string Prop controller: web_webview.WebviewController new web_webview.WebviewCont…...
微信换手机号了怎么绑定新手机号?
微信换手机号了怎么绑定新手机号? 1、在手机上找到并打开微信; 2、打开微信后,点击底部我的,并进入微信设置; 3、在微信设置账号与安全内,找到手机号并点击进入; 4、选择更换手机号,…...
64.WEB渗透测试-信息收集- WAF、框架组件识别(4)
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:63.WEB渗透测试-信息收集- WAF、框架组件识别(3)-CSDN博客 我们在…...
java.lang.LinkageError: 链接错误的正确解决方法,亲测有效,嘿嘿,有效
文章目录 问题分析报错原因解决思路解决方法(含代码示例)1. 检查类加载器2. 避免在运行时修改类定义3. 更新或修复 JVM4. 检查应用程序的依赖使用 Maven 检查依赖项使用 Gradle 检查依赖项 java.lang.LinkageError 是 Java 虚拟机在尝试链接类定义时发生…...
python最基础
基本的类 python最基础、最常用的类主要有int整形,float浮点型,str字符串,list列表,dict字典,set集合,tuple元组等等。int整形、float浮点型一般用于给变量赋值,tuple元组属于不可变对象&#…...
Python学习路线图(2024最新版)
这是我最开始学Python时的一套学习路线,从入门到上手。(不敢说精通,哈哈~) 一、Python基础知识、变量、数据类型 二、Python条件结构、循环结构 三、Python函数 四、字符串 五、列表与元组 六、字典与集合 最后再送给大家一套免费…...
66、基于长短期记忆 (LSTM) 网络对序列数据进行分类
1、基于长短期记忆 (LSTM) 网络对序列数据进行分类的原理及流程 基于长短期记忆(LSTM)网络对序列数据进行分类是一种常见的深度学习任务,适用于处理具有时间或序列关系的数据。下面是在Matlab中使用LSTM网络对序列数据进行分类的基本原理和流…...
RabbitMQ消息可靠性等机制详解(精细版三)
目录 七 RabbitMQ的其他操作 7.1 消息的可靠性(发送可靠) 7.1.1 confim机制(保证发送可靠) 7.1.2 Return机制(保证发送可靠) 7.1.3 编写配置文件 7.1.4 开启Confirm和Return 7.2 手动Ack(保证接收可靠) 7.2.1 添加配置文件 7.2.2 手动ack 7.3 避免消息重复消费 7.3.…...
88888
49615...
深度学习之激活函数
激活函数的公式根据不同的函数类型而有所不同。以下是一些常见的激活函数及其数学公式: Sigmoid函数: 公式:f(x)特性:输出范围在0到1之间,常用于二分类问题,将输出转换为概率值。但存在梯度消失问题&#…...
OpenStack开源虚拟化平台(一)
目录 一、OpenStack背景介绍(一)OpenStack是什么(二)OpenStack的主要服务 二、计算服务Nova(一)Nova组件介绍(二)Libvirt简介(三)Nova中的RabbitMQ解析 OpenS…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...










