(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

相关推荐
QC班长1 天前
Maven公司私库配置踩坑点
java·服务器·maven·intellij-idea
Makoto_Kimur1 天前
java开发面试-AI Coding速成
java·开发语言
审判长烧鸡1 天前
Go命名规则【2】全场景命名避坑指南
go·命名规则·ai问答
wuqingshun3141591 天前
说说mybatis的缓存机制
java·缓存·mybatis
知识浅谈1 天前
DeepSeek V4 和 GPT-5.5 在同一天发布了??我也很懵,但对比完我悟了
算法
蒸汽求职1 天前
跨越 CRUD 内卷:半导体产业链与算力基建下的软件工程新生态
人工智能·科技·面试·职场和发展·软件工程·制造
DeepModel1 天前
通俗易懂讲透 Q-Learning:从零学会强化学习核心算法
人工智能·学习·算法·机器学习
田梓燊1 天前
力扣:19.删除链表的倒数第 N 个结点
算法·leetcode·链表
空中海1 天前
Kubernetes 生产实践、可观测性与扩展入门
java·贪心算法·kubernetes
Devin~Y1 天前
大厂Java面试实录:Spring Boot/Cloud、Kafka、Redis、K8s 与 Spring AI(RAG/Agent)三轮连环问
java·spring boot·redis·mysql·spring cloud·kafka·kubernetes