LeetCode 53.最大子数组和:贪心算法下的连续子数组最优解

一、问题定义与核心挑战

1.1 问题描述

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

1.2 核心特征与难点

  • 子数组连续性:必须是原数组中连续的元素组成(与子序列不同)
  • 存在负数:数组中可能包含负数,增加了选择的复杂性(不能简单累加所有元素)
  • 最优子结构:最大子数组可能存在于数组的任意位置,需要高效定位

示例

  • 输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
  • 输出:6(对应子数组 [4,-1,2,1],和为6)

二、解题思路:贪心算法的局部最优到全局最优

2.1 核心思想

贪心算法的关键在于做出当前状态下的最优选择,并通过局部最优积累全局最优。对于本题:

  • 局部最优:若当前累加和为负数,继续累加会拖累后续子数组的和,因此应重置累加和(从下一个元素重新开始计算)
  • 全局最优:在遍历过程中,始终记录最大的累加和,即为最大子数组和

2.2 直观理解

可以将数组想象成一段起伏的路线,累加和是当前的海拔高度:

  • 当海拔为正时,继续前进可能达到更高海拔(保留当前累加和)
  • 当海拔为负时,继续前进只会更低,不如重新从当前位置出发(重置累加和)
  • 全程记录遇到的最高海拔,即为结果

三、代码逐行解析

3.1 初始化变量

int max = Integer.MIN_VALUE;  // 存储全局最大和,初始化为最小值避免负数场景出错
int cnt = 0;                  // 存储当前子数组的累加和

3.2 遍历数组计算

for (int i = 0; i < nums.length; i++) {
    cnt += nums[i];  // 累加当前元素到子数组和中
    
    // 更新全局最大值:比较当前子数组和与历史最大值
    max = Math.max(cnt, max);
    
    // 贪心决策:若当前累加和为负,重置为0(从下一个元素重新开始)
    if (cnt <= 0) {
        cnt = 0;
    }
}

3.3 返回结果

return max;  // 全局最大子数组和

四、算法执行过程演示

以示例 nums = [-2,1,-3,4,-1,2,1,-5,4] 为例,分步解析:

索引 i当前元素 nums[i]cnt 变化max 变化操作说明
0-20 + (-2) = -2max(-∞, -2) = -2cnt ≤0 → 重置为0
110 + 1 = 1max(-2, 1) = 1cnt 为正 → 保留
2-31 + (-3) = -2max(1, -2) = 1cnt ≤0 → 重置为0
340 + 4 = 4max(1, 4) = 4cnt 为正 → 保留
4-14 + (-1) = 3max(4, 3) = 4cnt 为正 → 保留
523 + 2 = 5max(4, 5) = 5cnt 为正 → 保留
615 + 1 = 6max(5, 6) = 6cnt 为正 → 保留
7-56 + (-5) = 1max(6, 1) = 6cnt 为正 → 保留
841 + 4 = 5max(6, 5) = 6循环结束

最终结果为 6,与预期一致。

五、核心逻辑深度解析

5.1 为什么重置累加和?

cnt ≤ 0 时,说明当前子数组的和已经是负数或零,继续带着这个和计算后续元素:

  • 若后续元素为正数,加上负数会比直接从该正数开始计算更小
  • 若后续元素为负数,加上负数会变得更小
  • 因此重置为0(相当于从下一个元素重新开始计算子数组和)是局部最优选择

5.2 为什么不需要记录子数组的起止位置?

题目只要求返回最大和,无需知道具体子数组的位置,因此只需通过 max 变量跟踪最大值即可,节省空间。

5.3 全负数场景的处理

当数组全为负数时(如 [-3, -1, -2]):

  • 每次累加后 cnt 都是负数,会被重置
  • max 会在每次累加后更新,最终保留最大的那个负数(即数组中最大的元素)
  • 符合“子数组最少包含一个元素”的要求

六、算法复杂度分析

  • 时间复杂度O(n),仅需遍历数组一次(n 为数组长度)
  • 空间复杂度O(1),仅使用常数个变量(maxcnt),与输入规模无关

七、常见误区与优化说明

7.1 误区1:初始值设置错误

若将 max 初始化为0,当数组全为负数时,会错误返回0(正确结果应为最大的负数)。因此必须初始化为 Integer.MIN_VALUE

7.2 误区2:重置条件判断错误

若将重置条件设为 cnt < 0(而非 cnt ≤ 0),当 cnt = 0 时不会重置,可能导致后续计算包含无意义的0(如数组 [0, -1] 会得到0,虽然结果正确,但逻辑不够严谨)。

7.3 与动态规划的关联

本题也可用动态规划求解(dp[i] = max(nums[i], dp[i-1] + nums[i])),但贪心算法更简洁,空间效率更高(动态规划若不优化空间为 O(n))。两种算法本质都是判断“是否保留之前的累加和”。

八、总结:贪心算法的适用场景

本题的贪心解法体现了“局部最优推导全局最优”的核心思想,适用于以下场景:

  • 问题可分解为一系列局部决策
  • 每个局部决策的最优选择能累积成全局最优
  • 无需回溯(每个决策一旦做出就不再修改)

最大子数组和问题通过简单的累加、比较、重置操作,在 linear 时间内解决,是贪心算法高效性的典型体现。掌握这种思路,可解决类似的连续序列优化问题(如最大乘积子数组等)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值