LeetCode No.53 最大子序和 java (分治算法) (2)

本文详细解析LeetCode第53题的最大子序和问题的分治算法解法。通过递归将数组不断拆分为更小的子数组,维护四个关键属性lSum、rSum、iSum和mSum,最终通过pushUp函数结合子数组信息求解原数组的最大子序列和。虽然分治法效率稍逊于贪心和动态规划,但其灵活性在处理大规模数据时更有优势。
摘要由CSDN通过智能技术生成


昨天(其实是前天),我阐述了这道题的贪心解法和动态规划解法,今天我来说说另一个方法—分治算法(这个算法的效率并没有贪心和动态规划的方法高效,但是它却和这两种方法有这相同的重要性)

题目

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [0]
输出:0

示例 4:

输入:nums = [-1]
输出:-1

示例 5:

输入:nums = [-100000]
输出:-100000

提示:
1 <= nums.length <= 3 * 104
-105 <= nums[i] <= 105

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

来源:力扣(LeetCode)
链接:LeetCode No.53 最大子序和


题解 分而治之

我们通过官方代码来讲解:
代码定义了一个函数:get(nums, left, right)表示获取nums数组中从left到right之间的最大子序列和,
所以我们要求的答案就应该是 get(nums, 0, nums.length() - 1),而要用分治的思路实现的话,则是从中间切开形成两个数组leftSubrightSub,而且一直递归形成这些数组,直到当数组长度为1时开始递归回溯:

m = (left + right) >> 1; (m = (left + right) / 2; )
leftSub = get(nums, left, m)
rightSub = get(nums, m + 1, right)
注意:这个地方rightSub的起始位置一定要从m + 1开始,否则会进行无限递归
我们一直进行分治肯定是想要获取一些量为目的的,而这些量是什么呢?如下我们来分析:

每一个数组我们需要获取并维护的都有四个属性:
lSum(从最左端点算起的最大子段和)
rSum(从最右端点算起的最大子段和)
mSum(整段数组的最大子序列)
iSum(整段数组的和)

我一开始很好奇为什么需要lSum 和rSum还有iSum这3个量,然后我发现,一个数组的最大子序列和就是由这几个量生成的,如下来看解释:
如果一个数组从中切成左右两边,则最大子序列mSum有三种可能:

  1. 全部在左边
  2. 全部在右边
  3. 在中间(跨越中间点)

第一种情况,我们会发现,该数组的mSum 就是 左段子数组的 mSum
第二种情况类似,该数组的mSum 就是 右段子数组的 mSum
第三种情况,我们可以得出mSum的值等于左段数组的rSum + 右段数组的lSum
由第三种情况而来rSum,lSum的意义

那么问题来了,rSum,lSum怎么求呢?
求一个数组的rSum,lSum,我们可以分两种情况讨论,我们以lSum为例讨论:

  1. 等于左段数组的lSum
  2. 等于左段数组的iSum
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值