真香!8 行代码搞定最大子数组和问题

87b9da238721b1f686992ed0faf0d84b.gif

作者 | 码农的荒岛求生

来源 | 码农的荒岛求生

今天给大家带来一道极其经典的题目,叫做最大和子数组,给定一个数组,找到其中的一个连续子数组,其和最大。

示例:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4] 

输出: 6 

解释: 子数组[4,-1,2,1]的和为6,其它任何连续的子数组和不超过6。

想一想该怎样解决这个问题。

如果你一时想不到解法可以从暴利解法开始。

暴力求解

这种解法最简单,我们把所有子数组找出来,然后依次计算其和,找出一个最大的出来,比如给定数组[1,2,3],那么我们能找出子数组:[1],[2],[3],[1,2],[2,3],[1,2,3],很显然这里和最大的子数组为[1,2,3],其值为6。

int sum(vector<int>&nums, int b,int e){int res = 0;for (; b <= e; b++) {res += nums[b];}return res;
}
int maxSubArray(vector<int>& nums) {int size = nums.size();int res = 0x80000000;for (int i = 0; i < size; i++) {for (int j = i; j < size; j++) {res = max(res, sum(nums, i, j));}}return res;
}

这种解法最简单,该算法的时间复杂度为O(n^3),其中找出所有子数组的时间复杂度为O(n^2),计算每个子数组的和的时间复杂度为O(n),因此其时间复杂度为O(n^3)。

让我们再来看一下这个过程,这里的问题在于计算每个子数组的和时有很多重复计算,比如我们知道了子数组[1,2]的和后再计算数组[1,2,3]的值时完全可以利用子数组[1,2]的计算结果而无需从头到尾再算一遍,也就是说我们可以利用上一步的计算结果,这本身就是动态规划的思想

a9483ce3fd70b0e50d68ea3117b7842d.png

基于该思想我们可以对上述代码简单改造一下:

int maxSubArray(vector<int>& nums) {int size = nums.size();int res = 0x80000000;for (int i = 0; i < size; i++) {int sumer = nums[i];res = max(res, sumer);for (int j = i + 1; j < size; j++) {sumer += nums[j];res = max(res, sumer);}}return res;
}

看到了吧,代码不但更简洁,而且运行速度更快,该算法的时间复杂度为O(n^2),比第一种解法高了很多。

还有没有进一步提高的空间呢?

答案是肯定的。

分而治之

我们可以把整个数组一分为二,然后子数组也一分为二,不断划分下去就像这样:

8662127c32d1bb7dbb5ef8b2f14e7151.png

然后呢?

然后问题才真正开始有趣起来,注意,当我们划分到最下层的时候,也就是不可再划分时会得到两个数组元素,比如对于数组[1,2]会划分出[1]与[2],此时[1]与[2]不可再划分,那么对于子问题[1,2],其最大子数组的和为max(1+2, 1,2),也就是说要么是左半部分的元素值、要么是右半部分的元素值、要么是两个元素的和,就这样我们得到了最后两层的答案:

ab0b9c5c1be3957396e1b84df8a03710.png

假设对于数组[1,2,3,4],一次划分后得到了[1,2]与[3,4],用上面的方法我们可以分别知道这两个问题的最大子数组和,我们怎样利用上述的答案来解决更大的问题,也就是[1,2,3,4]呢?

很显然,对于[1,2,3,4]来说,最大子数组的和要么来自左半部分、要么来自右半部分、要么来自中间部分——也就是包含2和3,其中左半部分和右半部分的答案我们有了,那么中间部分的最大和该是多少呢?

其实这个问题很简单,我们从中间开始往两边不断累加,然后记下这个过程的最大值,比如对于[1,-2,3,-4,5],我们从中间的3开始先往左边累加和是:{1+(-2)+3, (-2)+3, 3}也就是{2,1,3},因此我们以中间数字为结尾的最大子数组和为3:

68deb1a9e54b0541e7a88fb599f4f174.png

另一边也是同样的道理,只不过这次是以中间数字为起点向右累加:

6ce2e56716392d2e1df04470561b6cc6.png

然后这三种情况中取一个最大值即可,这样我们就基于子问题解决了更大的问题:

799f5f42d4e039094f762cca8599fed4.png

此后的道理一样,最终我们得到了整个问题的解。

根据上面的分析就可以写代码了:

int getMaxSum(vector<int>& nums, int b, int e) {if (b == e) return nums[b];if (b == e - 1) return max(nums[b], max(nums[e], nums[b]+nums[e]));int m = (b + e) / 2;int maxleft = nums[m];int maxright = nums[m];int sum = nums[m];for (int i = m + 1; i <= e; i++) {sum += nums[i];maxright = max(maxright, sum);}sum = nums[m];for (int i = m - 1; i >= b; i--) {sum += nums[i];maxleft = max(maxleft, sum);}return max(getMaxSum(nums, b, m - 1), max(getMaxSum(nums, m + 1, e), maxleft+maxright-nums[m]));
}
int maxSubArray(vector<int>& nums) {return getMaxSum(nums, 0, nums.size()-1);
}

上述这段代码的时间复杂度为O(NlogN)比第二种方法又提高了很多。

动态规划

实际上这个问题还有另一种更妙的解决方法,我们令dp(i)表示以元素A[i]为结尾的最大子数组的和,那么根据这一定义则有:

a77f305779a3ef3b19377e468d56adcb.png

这是很显然的,注意dp(i)的定义,是以元素A[i]为结尾的最大子数组的和,因此dp(i)的值要么就是A[i]连接上之前的一个子数组,那么不链接任何数组,那么最终的结果一定是以某个元素为结尾的子数组,因此我们从所有的dp(i)中取一个最大的就好了,依赖子问题解决当前问题的解就是所谓的动态规划。

有了这些分析,代码非常简单:

int maxSubArray(vector<int>& nums) {int size = nums.size();vector<int> dp(size, 0);int res = dp[0] = nums[0];for (int i = 1; i < size; i++) {dp[i] = max(dp[i - 1] + nums[i], nums[i]);res = max(res, dp[i]);}return res;
}

这段代码简单到让人难以置信,只有8行代码,你甚至可能会怀疑这段代码的正确性,但它的确是没有任何问题的,而且这段代码的时间复杂度只有O(N),这段代码既简单运行速度又快,这大概就是算法的魅力吧。

1ef1ec649999b36b8e24dae4cc5c7814.gif

85206e4525b61555be78b66b3efd4a3e.png

往期推荐

从 40% 跌至 4%,“糊”了的 Firefox 还能重回巅峰吗?

Gartner 发布 2022 年汽车行业五大技术趋势

别再用 Redis List 实现消息队列了,Stream 专为队列而生

漫画:什么是“低代码”开发平台?

fe093fa9445ad0d4d5355a59f1d90d5c.gif

点分享

d2244d32fec37da7f70479600f4c65e2.gif

点收藏

ce27b75cc300e616e231f534fb8548e6.gif

点点赞

8571783dd8a17ace006bf61f09caef3e.gif

点在看

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

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

相关文章

深度干货|云原生分布式数据库 PolarDB-X 的技术演进

简介&#xff1a; 深入解读PolarDB-X的产品架构&#xff0c;以及分布式事务、透明分布式、水平扩展等技术内幕。 一、PolarDB-X是什么 PolarDB-X最早起源于阿里集团2009年提出用分布式架构替代传统商业数据库&#xff0c;阿里研发了TDDL分库分表中间件。2014年阿里集团开始全…

OpenStack 如何跨版本升级

作者 | 孙琦来源 | 万博智云OpenStack是中国私有云的事实标准根据三方统计报告&#xff0c;2020年&#xff0c;中国私有云市场规模达到951.8亿元&#xff0c;同比增长42.1%&#xff0c;私有云在国内IaaS市场占比约45%。私有云提供商有望在云计算市场持续高速发展进程中持续受益…

流计算引擎数据一致性的本质

简介&#xff1a; 本篇文章从流计算的本质出发&#xff0c;重点分析流计算领域中数据处理的一致性问题&#xff0c;同时对一致性问题进行简单的形式化定义&#xff0c;提供一个一窥当下流计算引擎发展脉络的视角&#xff0c;让大家对流计算引擎的认识更为深入&#xff0c;为可能…

java 的io流需要学吗_Java的IO流之字节流,必须要学得内容,你会嘛?

原标题&#xff1a;Java的IO流之字节流&#xff0c;必须要学得内容&#xff0c;你会嘛&#xff1f;伙伴们~端午节过的如何呀~有没有很开心呀~假期已过咱们继续开动了IO流先来认识一下IO流&#xff1a;IO流用来处理设备之间的数据传输&#xff0c;Java对数据的操作是通过流的方式…

为什么大家都在抵制用定时任务实现「关闭超时订单」功能?

作者 | 阿Q来源 | 阿Q说代码前几天领导突然宣布几年前停用的电商项目又重新启动了&#xff0c;让我把代码重构下进行升级。让我最深恶痛觉的就是里边竟然用定时任务实现了“关闭超时订单”的功能&#xff0c;现在想来&#xff0c;哭笑不得。我们先分析一波为什么大家都在抵制用…

面对疾风吧,如何搭建高协同的精准告警体系?

简介&#xff1a; 想要实现AiOps&#xff0c;智能告警少不了。Arms 告警运维中心让面向告警的组织协同更加便捷高效&#xff01; 作者&#xff5c;九辩 世上没有一个系统是百分之百尽善尽美的。如果想要保证可用性&#xff0c;那么技术团队就得对服务的各种状态了如指掌&…

KubeMeet|聊聊新锐开源项目与云原生新的价值聚焦点

简介&#xff1a; 10 月 16 日上海&#xff0c;OAM/KubeVela、OpenKruise、OCM 三大开源项目的社区负责人、核心贡献者和企业用户将齐聚 KubeMeet&#xff0c;和现场 100 名开发者聊聊新的技术环境和企业需求下&#xff0c;有关“云原生应用管理”的那些事儿。 随着云原生关注…

Redis 究竟适不适合当队列来用?

‍作者 | Magic Kaito来源 | 水滴与银弹我经常听到很多人讨论&#xff0c;关于「把 Redis 当作队列来用是否合适」的问题。有些人表示赞成&#xff0c;他们认为 Redis 很轻量&#xff0c;用作队列很方便。也些人则反对&#xff0c;认为 Redis 会「丢」数据&#xff0c;最好还是…

EDA 事件驱动架构与 EventBridge 二三事

简介&#xff1a; 事件驱动型架构 (EDA) 方兴未艾&#xff0c;作为一种 Serverless 化的应用概念对云原生架构具有着深远影响。当我们讨论到一个具体架构时&#xff0c;首当其冲的是它的发展是否具有技术先进性。这里从我们熟悉的 MVC 架构&#xff0c;SOA 架构谈起&#xff0c…

如果被问到分布式锁,应该怎样回答?

作者 | tech-bus.七十一来源 | 程序员巴士说到锁&#xff0c;在平时的工作中&#xff0c;主要是使用synchronized关键字&#xff0c;或者相关的一些类库来实现同步&#xff0c;但这都是基于单机应用而言的&#xff0c;当我们的应用多实例部署时&#xff0c;这时候就需要用到分布…

工业视觉智能实战经验之IVI算法框架2.0

简介&#xff1a; 工业视觉智能团队在交付了多个工业视觉智能质检项目后&#xff0c;发现了工业视觉智能的共性问题和解法&#xff0c;打造了工业视觉智能平台&#xff0c;通过平台的方式积累和提升工业视觉的通用能力。在平台建设上最核心的能力是算法能力。算法能力包括不断增…

技术干货 | jsAPI 方式下的导航栏的动态化修改

简介&#xff1a; 操作指导&#xff1a;通过 jsAPI 实现导航栏的动态修改。 很多开发同学在接入 H5 容器后都会对容器的导航栏进行深度定制&#xff0c;除了 Native 的定制化之外&#xff0c;还有很多场景是使用到 jsAPI 的方式&#xff0c;通过 jsAPI 实现导航栏的动态修改。 …

Gartner:企业机构需重新定义网络安全领导者角色

编辑 | 宋慧 供稿 | Gartner 根据Gartner的最新调查&#xff0c;由于网络风险责任已被转移到IT以外&#xff0c;并且日益分散的生态系统导致网络安全领导者正在失去对决策的直接控制权&#xff0c;企业机构需要重新定义网络安全领导者的角色。 如今&#xff0c;安全和风险管理…

成本直降50%,下一代网关震撼发布

简介&#xff1a; 在容器和K8s主导的云原生时代&#xff0c;网关的新形态变得逐渐清晰&#xff0c;阿里内部也孵化出了下一代的网关产品 - 云原生网关&#xff0c;已在支付宝、淘宝、优酷、口碑等业务成功上线&#xff0c;并且经历了2020双11大促海量请求的考验&#xff0c;目前…

备战“双11”,阿里云为企业提供一站式资源保障服务

简介&#xff1a; 阿里云弹性计算将上线资源保障服务&#xff0c;通过智能化资源诊断、推荐、资源预定及授权候补为用户提供一站式自助化资源保障服务&#xff0c;兼顾灵活&#xff0c;经济的同时还能获得时刻的确定性保障&#xff0c;为业务顺畅前行保驾护航。 报名体验资源保…

快速上手 Serverless | 入门第一课

简介&#xff1a; 本文从云计算抛砖引玉&#xff0c;详解 Serverless 的典型应用场景和一些产品介绍。 一、 从云计算到 Serverless 自世界上第一台通用计算机 ENIAC (图左)诞生以来&#xff0c;计算机科学与技术的发展就从未停止过前进的脚步。2003年-2006年&#xff0c;谷歌…

钉钉宜搭邵磊:钉钉宜搭低代码加速业务互联 让改变发生

简介&#xff1a; 近日&#xff0c;在2021“低代码技术发展与应用线上研讨会”上&#xff0c;钉钉宜搭产品总监邵磊带来了“钉钉宜搭低代码加速业务互联 让改变发生”的主题演讲&#xff0c;详细介绍了钉钉宜搭低代码产品的六大互联能力。 宜搭是今年1月份正式上线到钉钉&…

Cloudera发布全球企业数据成熟度报告,混合云趋势中有效数据战略是关键

编辑 | 宋慧 出品 | CSDN云计算 2022年3月初&#xff0c;企业数据云公司Cloudera近日发布与技术市场研究公司Vanson Bourne联合编写的全球企业数据战略研究报告&#xff0c;报告分别洞察了数据的使用和价值、企业数据战略、企业数据发展趋势、企业业务计划四大部分的内容&…

基于海量日志和时序数据的质量建设最佳实践

简介&#xff1a; 在云原生和DevOps研发模式的挑战下&#xff0c;一个系统从开发、测试、到上线的整个过程中&#xff0c;会产生大量的日志、指标、事件以及告警等数据&#xff0c;这也给企业质量平台建设带来了很大的挑战。本议题主要通过可观测性的角度来讨论基于海量日志和时…

阿里云RDS深度定制-XA Crash Safe

简介&#xff1a; 近几年&#xff0c;随着分布式数据库系统的兴起&#xff0c;特别是基于MySQL分布式数据库系统&#xff0c;会用到XA来保证全局事务的一致性。众所周知&#xff0c;MySQL对XA事务的支持是比较弱的&#xff0c;存在很多问题。为了满足分布式数据库系统对XA事务的…