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] + 1f[i] = f[i - 1] + 1小于零的两种状态的情况:f[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1g[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;}
};

运行结果:
在这里插入图片描述

总结

通过本文的介绍,我们详细探讨了动态规划在解决子数组问题中的应用,具体分析了最大子数组和问题和最长递增子数组问题。这些问题在实际生活中的数据处理、优化等场景中有着广泛的应用。动态规划通过将问题分解为子问题,保存子问题的解,避免了重复计算,从而大大提高了算法的效率。

在学习和应用动态规划的过程中,我们需要明确状态、状态转移方程和初始条件。通过练习具体问题,我们可以更深入地理解动态规划的思想和方法。无论是最大子数组和问题还是最长递增子数组问题,掌握了动态规划的基本原理后,我们可以更灵活地应对其他类似的问题。

希望这篇文章能帮助你更好地理解动态规划在子数组问题中的应用。如果你有任何问题或建议,欢迎在评论区留言,我们将尽力为你解答。祝你在学习动态规划和解决实际问题的过程中取得更多的进步!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

音视频开发31 FFmpeg 编码- avcodec_find_encoder和avcodec_find_encoder_by_name

avcodec_find_encoder /** * Find a registered encoder with a matching codec ID. * * param id AVCodecID of the requested encoder * return An encoder if one was found, NULL otherwise. */ AVCodec *avcodec_find_encoder(enum AVCodecID id); 那么这个 AVCodec…

14分Top刊NC代码开源|NSCLC单细胞+空转肿瘤微环境分析

说在前面 说起肺癌真的过去回忆历历在目&#xff0c;小编毕业后职业生涯的第一个项目——非小细胞肺癌预后有效靶点筛选。当时肝的是转录组预后建模筛选。 做研发其实要求是远远高于发文章的&#xff0c;文章投不出去就降分&#xff0c;加工作量&#xff0c;做药要是烂尾或者…

2024年7月1日 (周一) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 喜马拉雅下载工具: 字面意思 《星刃》早期概念图分享 末世破败环境推主Genki分享了《星…

Spire.PDF for .NET【文档操作】演示:在 PDF 中创建目录 (TOC)

目录在增强文档的可读性和可导航性方面起着至关重要的作用。它为读者提供了文档结构的清晰概述&#xff0c;使他们能够快速找到并访问他们感兴趣的特定部分或信息。这对于较长的文档&#xff08;例如报告、书籍或学术论文&#xff09;尤其有价值&#xff0c;因为读者可能需要多…

部署calico网络插件

部署calico网络插件 之前的k8s环境中主要使用了flannel作为网络插件&#xff0c;这次改用calico。calico支持多种安装方式&#xff0c;以下是具体的操作步骤。 1. 准备工作 环境信息 # 系统信息 rootmaster1:~# cat /etc/issue Ubuntu 24.04 LTS \n \lrootmaster1:~# uname…

MyBatisPlus 常用的注解 表映射 主键映射 字段映射

介绍 官网&#xff1a;https://baomidou.com/reference/annotation/ 指定映射表 实体类使用驼峰命名&#xff0c;表名应为xx_xxx等格式这样才可以映射&#xff0c;但是实际开发过程中可能不一致就可以使用该方法处理。 Data TableName("employee_235") //映射的表…

求质数题目

//需求:键盘录入一个正整数x&#xff0c;判断该整数是否为一个质数。 //质数: //如果一个整数只能被1和本身整除&#xff0c;那么这个数就是质数。否则这个数叫做合数 package Base_se.Base_701;import java.util.Scanner;/*** author gyf* ClassName test* Date 2024/7/1 19:…

Linux启动elasticsearch,提示权限不够

Linux启动elasticsearch&#xff0c;提示权限不够&#xff0c;如下图所示&#xff1a; 解决办法&#xff1a; 设置文件所有者&#xff0c;即使用户由权限访问文件 sudo chown -R 用户名[:新组] ./elasticsearch-8.10.4 //切换到elasticsearch-8.10.4目录同级 chown详细格式…

银行家算法-操作系统中避免死锁的最著名算法

背景 有很多文章都会介绍银行家算法。在百度和CSDN上搜一搜能搜出很多来。很多同学会觉得这个算法很深奥&#xff0c;有些文章写的又很复杂&#xff0c;其实真的很简单。这里简单记录一下基本原理&#xff0c;然后大家再配合其他文章看&#xff0c;就能加深理解。 算法原理 …

LLaVA1.5训练数据和时间分析

LLaVA的PT+SFT训练_llava sft-CSDN博客文章浏览阅读379次。这个阶段,使用8个A100(80G)训练LLaVA-v1.5-13B大约需要20h。全量微调,非lora跑不起来啊,以前一直用swift,llama-factory这种框架式的代码库,但用原作者开源的代码也是有很多好处的。在这个阶段,使用 8 个 A100(…

Oracle中 ROW_NUMBER()的语法及在对应不同需求下应如何使用

Oracle数据库中的ROW_NUMBER()函数是一个窗口函数&#xff0c;它为查询结果集中的每一行分配一个唯一的序号。这个函数在数据分析、分页查询、数据去重和排名问题等方面非常有用。ROW_NUMBER()函数的语法如下&#xff1a; ROW_NUMBER() OVER ( [ PARTITION BY column ] ORDER …

3.用户程序与驱动交互

驱动程序请使用第二章https://blog.csdn.net/chenhequanlalala/article/details/140034424 用户app与驱动交互最常见的做法是insmod驱动后&#xff0c;生成一个设备节点&#xff0c;app通过open&#xff0c;read等系统调用去操作这个设备节点&#xff0c;这里先用mknode命令调…

64.WEB渗透测试-信息收集- WAF、框架组件识别(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;63.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;3&#xff09;-CSDN博客 我们在…

【FedMut】Generalized Federated Learning via Stochastic Mutation

基于随机变异的泛化联邦学习 来源&#xff1a;AAAI2024 Abstract 问题&#xff1a; FedAvg 将相同的全局模型派发给客户端进行本地训练&#xff0c;容易陷入尖锐解&#xff0c;导致训练出性能低下的全局模型 提出 FedMut&#xff1a; 本文提出了一种名为 FedMut 的新型FL方法…

2024免费的股票数据接口API

沧海数据 # Restful API https://tsanghi.com/api/fin/stock/{exchange_code}/realtime?token5dbb47113a4a43a6be1755673ce854db&ticker{ticker} 数据来源&#xff1a;沧海数据 请求方式&#xff1a;Get 数据格式&#xff1a;标准Json格式[{},...{}]

如何借用物联网快速实现高标准农田信息化

如何借用物联网快速实现高标准农田信息化 高标准农田信息化&#xff0c;作为现代农业发展的重要基石&#xff0c;是指在建设高产、稳产、节水、环保的农田基础上&#xff0c;深度融合现代信息技术&#xff0c;实现农田管理的精准化、智能化和高效化。物联网&#xff08;Intern…

vue3+ts实现计算两个字符串的相似度

在TypeScript中&#xff0c;可以使用Levenshtein莱文斯坦距离算法来精确匹配两个字符串的相似度百分比。Levenshtein距离是指两个字符串之间&#xff0c;由一个转换成另一个所需的最少编辑操作次数&#xff0c;这里的编辑操作包括插入、删除、替换。 /*** Levenshtein距离算法…

Linux Static calls机制

文章目录 前言一、简介二、Background: indirect calls, Spectre, and retpolines2.1 Indirect calls2.2 Spectre (v2)2.3 RetpolinesConsequences 2.4 Static callsHow it works 三、其他参考资料 前言 Linux内核5.10内核版本引入新特性&#xff1a;Static calls。 Static c…

JAVA各版本-安装教程

目录 Java安装包下载 Java安装步骤 Java环境配置 Java安装包下载 到Oracle官网下载自己需要的版本 Oracle Java下载&#xff1a;Java Archive | Oracle Hong Kong SAR, PRC 下拉选择自己需要的版本&#xff08;本教程以Windows环境下&#xff0c;JAVA11为例&#xff09; 注…

C++初学者指南-3.自定义类型(第一部分)-指针

C初学者指南-3.自定义类型(第一部分)-指针 文章目录 C初学者指南-3.自定义类型(第一部分)-指针1.为什么我们需要它们&#xff1f;2.T 类型的对象指针原始指针&#xff1a;T * 智能指针(C11) 3.操作符地址操作符 &解引用运算符 *成员访问操作符 ->语法重定向 4.nullptr (…