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

问题简介

LeetCode 53. 最大子数组和

题目描述

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

子数组 是数组中的一个连续部分。


📌 示例说明

示例 1:

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

示例 2:

复制代码
输入:nums = [1]
输出:1

示例 3:

复制代码
输入:nums = [5,4,-1,7,8]
输出:23

💡 解题思路

方法一:动态规划(Kadane 算法)✅(推荐)

这是解决最大子数组和问题最经典、最高效的方法。

思路步骤:

  1. 定义状态 :设 dp[i] 表示以 nums[i] 结尾的最大子数组和。
  2. 状态转移方程
    • 如果 dp[i-1] > 0,那么 dp[i] = dp[i-1] + nums[i](加上前面的正收益)
    • 否则 dp[i] = nums[i](从当前重新开始)
    • 可简化为:dp[i] = max(nums[i], dp[i-1] + nums[i])
  3. 初始化dp[0] = nums[0]
  4. 结果 :所有 dp[i] 中的最大值

实际上我们不需要保存整个 dp 数组,只需维护一个变量记录当前最大子数组和即可,空间复杂度可优化到 O(1)。


方法二:分治法(了解即可)

将数组分为左右两半,最大子数组和可能出现在:

  • 左半部分
  • 右半部分
  • 跨越中点的部分

递归求解左右部分,再计算跨越中点的最大和,取三者最大值。

时间复杂度 O(n log n),不如 Kadane 算法高效,但有助于理解分治思想。


方法三:暴力枚举(❌ 不推荐)

双重循环枚举所有子数组,计算和并更新最大值。

时间复杂度 O(n²),在 LeetCode 上会超时。


💻 代码实现

java 复制代码
// Java 实现 - 动态规划(Kadane 算法)
class Solution {
    public int maxSubArray(int[] nums) {
        int maxSum = nums[0];      // 全局最大和
        int currentSum = nums[0];  // 当前子数组和
        
        for (int i = 1; i < nums.length; i++) {
            // 决定是继续累加还是从当前元素重新开始
            currentSum = Math.max(nums[i], currentSum + nums[i]);
            // 更新全局最大值
            maxSum = Math.max(maxSum, currentSum);
        }
        
        return maxSum;
    }
}
go 复制代码
// Go 实现 - 动态规划(Kadane 算法)
func maxSubArray(nums []int) int {
    maxSum := nums[0]      // 全局最大和
    currentSum := nums[0]  // 当前子数组和

    for i := 1; i < len(nums); i++ {
        // 决定是继续累加还是从当前元素重新开始
        if currentSum+nums[i] > nums[i] {
            currentSum += nums[i]
        } else {
            currentSum = nums[i]
        }
        // 更新全局最大值
        if currentSum > maxSum {
            maxSum = currentSum
        }
    }

    return maxSum
}

🧪 示例演示

nums = [-2,1,-3,4,-1,2,1,-5,4] 为例:

i nums[i] currentSum(当前子数组和) maxSum(全局最大)
0 -2 -2 -2
1 1 1 1
2 -3 -2 1
3 4 4 4
4 -1 3 4
5 2 5 5
6 1 6 6
7 -5 1 6
8 4 5 6

✅ 最终返回 6,对应子数组 [4, -1, 2, 1]


✅ 答案有效性证明

数学归纳法简要证明 Kadane 算法正确性:

  • 基础情况:当数组只有一个元素时,算法返回该元素,显然正确。
  • 归纳假设 :假设对于前 k 个元素,currentSum 正确表示以第 k 个元素结尾的最大子数组和。
  • 归纳步骤 :考虑第 k+1 个元素:
    • currentSum > 0,加上 nums[k+1] 一定比单独 nums[k+1] 更优;
    • currentSum ≤ 0,则从 nums[k+1] 重新开始更优。
    • 因此 currentSum = max(nums[k+1], currentSum + nums[k+1]) 正确。

同时,maxSum 始终记录历史最大值,故最终结果正确。


📊 复杂度分析

方法 时间复杂度 空间复杂度 是否最优
动态规划(Kadane) O(n) O(1) ✅ 是
分治法 O(n log n) O(log n) ❌ 否
暴力枚举 O(n²) O(1) ❌ 否

Kadane 算法是最优解:线性时间,常数空间。


📌 问题总结

  • 核心思想:贪心 + 动态规划。只要当前累计和为正,就值得保留;否则果断舍弃,从新位置开始。
  • 关键洞察:最大子数组和一定是以某个位置结尾的子数组中的最大值。
  • 应用场景:股票最大收益(一次交易)、信号处理中的峰值检测等。
  • 扩展思考
    • 如果要求返回子数组的起止索引?→ 可额外记录起始位置。
    • 如果数组全为负数?→ 算法仍有效,返回最大负数。
    • 环形数组最大子数组和?→ LeetCode 918,需结合总和与最小子数组和。

💡 记住 Kadane 算法模板
current = max(nums[i], current + nums[i])
global_max = max(global_max, current)

github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions

相关推荐
生成论实验室1 小时前
即事经:一种基于生成论的宇宙、生命与文明新范式
人工智能·科技·神经网络·算法·信息与通信
王老师青少年编程2 小时前
csp信奥赛c++高频考点假期集训(分模块进阶)
数据结构·c++·算法·csp·高频考点·信奥赛·集训
百锦再2 小时前
Java之Volatile 关键字全方位解析:从底层原理到最佳实践
java·开发语言·spring boot·struts·kafka·tomcat·maven
张万森爱喝可乐2 小时前
Java高并发实战
java
daad7772 小时前
rcu 内核线程
java·开发语言
百锦再3 小时前
Java JUC并发编程全面解析:从原理到实战
java·开发语言·spring boot·struts·kafka·tomcat·maven
癫狂的兔子3 小时前
【Python】【机器学习】K-MEANS算法
算法·机器学习·kmeans
Bear on Toilet4 小时前
递归_二叉树_50 . 从前序与中序遍历序列构造二叉树
数据结构·算法·leetcode·深度优先·递归