动态规划算法专题四--子数组系列问题

news2024/9/26 3:30:46

目录

 

题十八 最大子数组和

1、算法解析

1、确定状态:

2、状态转移方程:

3、初始化:

4、填表顺序:

5、返回值:

2、代码

 题十九 环形子数组的最大和

1、算法解析

1、确定状态:

2、状态转移方程:

3、初始化:

4、填表顺序:

5、返回值:

2、代码

 题二十 乘积最大子数组

1、算法解析

1、确定状态:

2、状态转移方程:

3、初始化:

4、填表顺序:

5、返回值:

2、代码

  题二十一 乘积为正数的最长子数组


 

题十八 最大子数组和

53. 最大子数组和 - 力扣(LeetCode)

1、算法解析

1、确定状态:

dp[i]位置的值,表示以i为结尾的子数组的最大和。注意,是以i为结尾,并没有规定从那个位置开始。

2、状态转移方程:

i位置有两种状态:长度为1,长度大于1。
长度为1时,以i结尾,就是i位置的值,即nums[i]
长度大于1时,以i结尾,就是要包括前面i-1位置的和,即dp[i-1] + nums[i]

3、初始化:

初始化解决的是填表越界的问题
根据状态转移方程,我们需要初始化dp[0]的位置
第一个,因为必须包含一个元素,所以只能是其本身值
即dp[0] = n[0]

4、填表顺序:

从左往右

5、返回值:

我们不知道最大值到底是以那个位置为结尾的连续子数组,因此要遍历拿出最大值。

2、代码

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        //1、创建dp表
        int n = nums.size();
        if(n==1) return nums[0];
        vector<int> dp(n);

        //2、初始化
        dp[0] = nums[0];

        //3、填表
        for(int i = 1; i<n; ++i)
        {
            dp[i] = max(nums[i], dp[i-1] + nums[i]);
        }

        //4、返回值
        int ret = -0x3f3f3f3f;
        for(int i = 0; i<n; ++i)
        {
            if(dp[i] >= ret)
            {
                ret = dp[i];
            }
        }
        return ret;

    }
};

 题十九 环形子数组的最大和

918. 环形子数组的最大和 - 力扣(LeetCode)

1、算法解析

这一题比简单的线性最大数组和多了一个环形。
我们怎么做呢?
可以不可以把环形,变成线性的数组?
如果转化为线性的数组,那就是最大连续子数组和
我们仔细研究一下这个环形,会发现:答案就只有两种可能
一个是最大连续字数组就在中间位置:
一个是最大连续子数组在两边连接处:

这第二种情况,我们会发现中间的连续子数组是最小的。
那么数组的最大值就是整个数组的和-最小连续子数组。
那么,我们就来比较这两种情况那个大即可。

1、确定状态:

我们需要两个表,一个f求最小值,一个g求最大值:
f[i]位置的值,表示以i为结尾的最小连续子数组和。注意,是以i为结尾,并没有规定从那个位置开始。
g[i]位置的值,表示以i为结尾的最大连续子数组和。注意,是以i为结尾,并没有规定从那个位置开始。

2、状态转移方程:

i位置有两种状态:长度为1,长度大于1。
长度为1时,以i结尾,就是i位置的值,即nums[i]
长度大于1时,以i结尾,就是要包括前面i-1位置的和,即f[i-1] + nums[i]

f[i] = min(nums[i], f[i-1] + nums[i]);
g[i] = max(nums[i], g[i-1]  + nums[i]);
一个求最大,一个求最小。

3、初始化:

初始化解决的是填表越界的问题
根据状态转移方程,我们需要初始化f[0]的位置
f[0] = nums[0]
g[0] = nums[0]

4、填表顺序:

从左往右

5、返回值:

找出最大值,和sum-最小值对比,返回大者。
但是,需要注意,如果所有的数组都是负数,最小值就是所有数字的和。
sum - min = 0;就会返回0
但是返回值不能是0,因为必须包含一个元素。
所以需要特别判断

2、代码
 

class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        //1、创建dp表
        int n = nums.size();
        if(n == 1) return nums[0];
        vector<int> f(n);
        auto g = f; 

        int sum = 0;
        for(auto e : nums)
        {
            sum += e;
        }

        //2、初始化
        f[0] = nums[0];
        g[0] = nums[0];

        //3、填表
        for(int i = 1; i<n; ++i)
        {
            f[i] = min(nums[i], f[i-1] + nums[i]);//找最小值
            g[i] = max(nums[i], g[i-1] + nums[i]);//找最大值
        }

        //4、返回值
        int max_value  = -0x3f3f3f3f;
        int min_value = 0x3f3f3f3f;
        for(int i= 0; i<n; ++i)
        {
            if(g[i] >= max_value)
                max_value = g[i];
            if(f[i] <= min_value)
                min_value = f[i];
        }
        
        if(sum == min_value)
            return max_value;
        
        return max(max_value, sum - min_value);


    }
};

 题二十 乘积最大子数组

152. 乘积最大子数组 - 力扣(LeetCode)

1、算法解析

1、确定状态:

也是一个连续子数组求最大最小的问题。
我们创建一个一维dp表。
dp[i]的值,表示以i为结尾的最大乘积子数组,注意,并没有规定是从那个位置作为开始位置。

2、状态转移方程:

i位置有两种状态:长度为1,长度大于1。
长度为1时,以i结尾,就是i位置的值,即nums[i]
长度大于1时,以i结尾,就是要包括前面i-1位置的和,即dp[i-1] * nums[i]

按照原来的逻辑,上述的推导是没有问题的。
但是,如果nums[i]是一个负数,dp[i-1]是一个最大值,那么最大值×负数,直接变成最小值。
出问题了。
正确的逻辑应该是:
如果nums[i]是一个正数,那么dp[i-1]的值,应该是最大值
如果nums[i]是一个负数,那么dp[i-1]的值,应该是最小值。
所以,按照我们的逻辑推导,我们需要两个状态表:
f[i]代表表示以i为结尾的最大乘积子数组
g[i]代表表示以i为结尾的最小乘积子数组
如图:

3、初始化:

初始化解决的是填表越界的问题
根据状态转移方程,我们需要初始化f[0]的位置
f[0] = g[0] = nums[0];

4、填表顺序:

从左往右

5、返回值:

返回f表中的最大值。

2、代码

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        //1、创建dp表
        int n = nums.size();
        if(n == 1) return nums[0];

        vector<int > f(n);
        auto g =f;

        //2、初始化
        f[0] = g[0] = nums[0];

        //f[i]为最小值
        //g[i]为最大值

        //3、填表
        for(int i = 1; i<n; ++i)
        {
            f[i] = min(nums[i], min(g[i-1] * nums[i], f[i-1] * nums[i]));
            g[i] = max(nums[i], max(f[i-1] * nums[i], g[i-1] * nums[i]));
        }
        
        //4、返回值
        int  ret = INT_MIN;
        for(int i = 0; i<n; ++i)
        {
            if(g[i] >= ret) 
                ret = g[i];
        }

        return ret;
    }
};

  题二十一 乘积为正数的最长子数组

152. 乘积最大子数组 - 力扣(LeetCode)

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

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

相关文章

浅析Kafka-Stream消息流式处理流程及原理

以下结合案例&#xff1a;统计消息中单词出现次数&#xff0c;来测试并说明kafka消息流式处理的执行流程 Maven依赖 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><exclusio…

OpenCV:python图像旋转,cv2.getRotationMatrix2D 和 cv2.warpAffine 函数

前言 仅供个人学习用&#xff0c;如果对各位朋友有参考价值&#xff0c;给个赞或者收藏吧 ^_^ 一. cv2.getRotationMatrix2D(center, angle, scale) 1.1 参数说明 parameters center&#xff1a;旋转中心坐标&#xff0c;是一个元组参数(col, row) angle&#xff1a;旋转角度…

Kafka基础组件图推演

文章目录 1. Controller Broker保障机制 2. 组件架构1. Log Manager2. Replication Manager3. SocketServer4. NetworkServer5. ZKClient 1. Controller Broker Kafka集群中有一个Controller Broker&#xff0c;负责元数据管理和协调。 Kafka使用Zookeeper作为集群元数据的存储…

利用js实现图片压缩功能

图片压缩在众多应用场景中扮演着至关重要的角色&#xff0c;尤其是在客户端上传图片时。原始图片往往体积庞大&#xff0c;直接上传不仅消耗大量带宽资源&#xff0c;还可能导致上传速度缓慢&#xff0c;严重影响用户体验。因此&#xff0c;在图片上传至服务器前对其进行压缩处…

【安全设备】入侵检测

一、什么是入侵检测 入侵检测是一种网络安全技术&#xff0c;用于监测和识别对计算机系统或网络的恶意使用行为或未经授权的访问。入侵检测系统&#xff08;IDS&#xff09;是实现这一目标的技术手段&#xff0c;其主要目的是确保计算机系统的安全&#xff0c;通过及时发现并报…

Renesas R7FA8D1BH (Cortex®-M85) 控制DS18B20

目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP和KEIL配置 2.1 硬件接口电路 2.2 FSB配置DS18B20的IO 2.3 生成Keil工程文件 3 DS18B20驱动代码 3.1 DS18B20介绍 3.2 DS18B20驱动实现 3.2.1 IO状态定义 3.2.2 读IO状态函数 3.2.3…

谷粒商城实战笔记-27-分布式组件-SpringCloud-Gateway-创建测试API网关

本节的主要内容是创建网关模块&#xff0c;将网关注册到Nacos&#xff0c;并配置路由进行测试。 一&#xff0c;创建网关模块 右键工程New->Module&#xff0c;创建新模块&#xff0c;模块名称 gulimall-gateway。 填充各种信息。 选中Gateway依赖。 点击Create创建模块。…

uni-app iOS上架相关App store App store connect 云打包有次数限制

相册权限 uni-app云打包免费有次数 切换一个账号继续

C语言 | Leetcode C语言题解之第230题二叉搜索树中第K小的元素

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int search_num(struct TreeNode* root, int k, int *result, int num) {if(num k 1){retu…

JAVA之(static关键字、final关键字、抽象类、接口)

JAVA之&#xff08;static关键字、final关键字&#xff09; 一、 static关键字1、静态变量2、静态方法3、 静态代码块4、例子 二、final关键字1、final修饰类2、 final修饰方法3、修饰变量 三、抽象类1、 抽象类 四、接口 一、 static关键字 1、静态变量 private static Stri…

Java异常体系、UncaughtExceptionHandler、Spring MVC统一异常处理、Spring Boot统一异常处理

概述 所有异常都是继承自java.lang.Throwable类&#xff0c;Throwable有两个直接子类&#xff0c;Error和Exception。 Error用来表示程序底层或硬件有关的错误&#xff0c;这种错误和程序本身无关&#xff0c;如常见的NoClassDefFoundError。这种异常和程序本身无关&#xff0…

学习大数据DAY14 PLSQL基础语法3

目录 二重循环 三种循环随便嵌套 exit continue return 作业 数据提取 游标 隐式游标 显示游标 动态游标 游标使用流程 游标属性 游标配合循环使用示例 作业2 参数游标 current of 语句 作业3 PLSQL基础语法&#xff08;三&#xff09; 二重循环 三种循环随便嵌…

threadLocal详细认识(使用场景与局限性)与样例测试

Threadlocal的介绍与使用 1&#xff0c;是什么&#xff1f; ThreadLocal 是 Java 提供的一个工具类&#xff0c;用于在多线程环境中为每个线程提供独立的变量副本。它是 Java 标准库中的一部分&#xff0c;提供了线程局部存储的功能&#xff0c;这意味着每个线程都有自己独立…

【安全设备】APT攻击预警平台

一、什么是APT 高级持续性威胁&#xff08;APT&#xff09;是一种高度复杂和长期的网络攻击&#xff0c;旨在通过持续监视和访问特定目标来窃取敏感信息或进行其他恶意活动。这种攻击结合了多种先进的技术手段和社会工程学方法&#xff0c;以极高的隐蔽性实现长期潜伏和信息窃…

2 文件

2 文件 1、文件系统1.1 文件系统的逻辑结构1.2 文件的访问流程 2、文件类型3、文件的打开与关闭4、文件的内核结构5、文件的读写4.1 顺序与随机读写4.2 文件描述符的复制4.3 访问测试4.4 修改文件大小 5、文件锁5.1 读写冲突5.2 文件锁5.3 文件锁的内核结构 6、文件的元数据7、…

MTK Camera 冷启动、前后摄切换性能优化分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、背景二、问题分解三、工具分析四、 traceView教程五、surface create优化六、systrace的教程七、优化方案八、前后切换速度优化九、优化方案十、热…

旷野之间4 - 100 个 Kubernetes 面试问题及答案

100 个 Kubernetes 面试问题及答案 Kubernetes 简介 什么是 Kubernetes&#xff1f; Kubernetes 是一个开源容器编排平台&#xff0c;可自动部署、扩展和管理容器化应用程序。 什么是容器&#xff1f; 容器是一个轻量级、独立的、可执行软件包&#xff0c;其中包含运行应用…

学习笔记——动态路由——IS-IS中间系统到中间系统(特性之路由撤销)

6、路由撤销 ISIS路由协议的路由信息是封装在LSP报文中的TLV中的&#xff0c;但是它对撤销路由的处理和OSPF的处理方式类似。 在ISIS中撤销一条路由实则是将接口下的ISIS关闭&#xff1a; 撤销内部路由&#xff1a; 在ISIS中路由信息是由IP接口TLV和IP内部可达性TLV共同来描…

游戏AI的创造思路-技术基础-决策树(2)

上一篇写了决策树的基础概念和一些简单例子&#xff0c;本篇将着重在实际案例上进行说明 目录 8. 决策树应用的实际例子 8.1. 方法和过程 8.1.1. 定义行为 8.1.2. 确定属性 8.1.3. 构建决策树 8.1.4. 实施行为 8.1.5. 实时更新 8.2. Python代码 8. 决策树应用的实际例子…

hudi数据湖万字全方位教程+应用示例

1、时间轴&#xff08;TimeLine&#xff09; Hudi的核心是维护表上在不同的即时时间&#xff08;instants&#xff09;执行的所有操作的时间轴&#xff08;timeline&#xff09;&#xff0c;这有助于提供表的即时视图 一个instant由以下三个部分组成&#xff1a; 1&#xff09;…