(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 numsi 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

相关推荐
程序员黑豆2 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
GreenTea2 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
风流 少年2 小时前
Spring AI 2.0:Memory
java·后端·spring
码匠许师傅3 小时前
【C++ 面试真题】聊聊 C++ 的移动语义与右值引用
java·c++·面试
小席是个热心肠3 小时前
AI相关的自我学习
java·人工智能·学习
fqq33 小时前
力扣刷题前置Java语法
算法·leetcode·职场和发展
Thecozzy5 小时前
大厂 AI Coding 面试大招
人工智能·面试·职场和发展
数智化管理手记6 小时前
海量数据如何沉淀有效数据资产?数据标准化治理方案如何搭建?
java·大数据·人工智能
半夏微凉半夏殇6 小时前
x11与weston对比,优先选哪个
leetcode·均值算法·eclipse
2501_906565126 小时前
数学之美探究
算法