(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

相关推荐
DeepModel12 分钟前
【概率分布】Beta分布详解
算法·概率论
我命由我1234520 分钟前
React - 验证 Diffing 算法、key 的作用
javascript·算法·react.js·前端框架·html·html5·js
@PHARAOH2 小时前
HOW - Kratos 入门实践(二)- 概念学习
前端·微服务·go
无心水3 小时前
【OpenClaw:实战部署】5、全平台部署OpenClaw(Win/Mac/Linux/云服务器)——10分钟跑通第一个本地AI智能体
java·人工智能·ai·智能体·ai智能体·ai架构·openclaw
一只大袋鼠4 小时前
Redis 安装+基于短信验证码登录功能的完整实现
java·开发语言·数据库·redis·缓存·学习笔记
Eward-an4 小时前
LeetCode 1980 题通关指南|3种解法拆解“找唯一未出现二进制串”问题,附Python最优解实现
python·算法·leetcode
程序员酥皮蛋4 小时前
hot 100 第四十题 40.二叉树的层序遍历
数据结构·算法·leetcode
※DX3906※5 小时前
Java排序算法--全面详解面试中涉及的排序
java·开发语言·数据结构·面试·排序算法
木斯佳5 小时前
HarmonyOS 6实战:从爆款vlog探究鸿蒙智能体提取关键帧算法
算法·华为·harmonyos
cur1es6 小时前
【JVM类加载&双亲委派模型&垃圾回收机制】
java·jvm·gc·垃圾回收·类加载·双亲委派模型