力扣hot100之最大子数组和(Java版)

1、题目描述

给你一个整数数组 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

2、解法

方法一:暴力

bash 复制代码
import java.util.ArrayList;
import java.util.Collections; // 需要导入 Collections 来使用 max 方法

class Solution {
    public int maxSubArray(int[] nums) {
        ArrayList<Integer> result = new ArrayList<>();

        // 外层循环:确定子数组的起始位置
        for (int i = 0; i < nums.length; i++) {
            int sum = 0; // 每次换起始位置时,重置和

            // 内层循环:确定子数组的结束位置,并累加求和
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];       // 累加当前元素
                result.add(sum);      // 每累加一次,就得到了一个以 i 开头、j 结尾的子数组的和,存入列表
            }
        }

        //使用 Collections.max() 来获取列表中的最大值
        return Collections.max(result);
    }
}

这种方法虽然可以,但是时间复杂度为O(n^2),当数据非常大的时候,会超出内存限制。

方法二:进阶版

虽然上面的代码可以通过部分测试,但使用 ArrayList 存储所有的和会消耗大量内存(空间复杂度较高)。其实不需要把所有和都存下来,只需要用一个变量 max 记录当前遇到的最大值即可。

bash 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        // 初始化最大值为整数最小值,防止数组全是负数时出错
        int max = Integer.MIN_VALUE;

        for (int i = 0; i < nums.length; i++) {
            int sum = 0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                // 每次算出新和,直接比较并更新最大值
                if (sum > max) {
                    max = sum;
                }
            }
        }
        return max;
    }
}

这种呢,也能通过,虽然比上面第一种方法通过的多一点,但是不能全部通过案例

方法三:动态规划

动态规划是一种通过将复杂问题分解为更简单的子问题,并存储这些子问题的解以避免重复计算,从而高效求解最优化问题的算法设计方法。 ------ 源自《算法导论》(Introduction to Algorithms, CLRS)

其核心基于两个数学性质:

  1. 最优子结构(Optimal Substructure) 问题的最优解包含其子问题的最优解。

  2. 重叠子问题(Overlapping Subproblems) 在递归求解过程中,相同的子问题被多次重复计算。


动态规划设计的核心知识点(标准步骤):

1. 定义状态(State)
  • 用一个变量或数组 dp[i]dp[i][j] 等表示子问题的解

  • 例如:dp[i] 表示"前 i 个元素中能获得的最大和"。

2. 确定状态转移方程(Recurrence Relation)
  • 描述当前状态如何由之前的状态推导而来。

  • 例如:dp[i] = max(dp[i-1] + nums[i], nums[i])(最大子数组和)

3. 设定初始条件(Base Case)
  • 最简单子问题的解,作为递推起点。

  • 例如:dp[0] = nums[0]

4. 确定计算顺序(Order of Computation)
  • 通常自底向上(Bottom-up):从小到大填表(如 for 循环)

  • 也可自顶向下(Top-down):递归 + 记忆化(Memoization)

5. 空间优化(可选)
  • 若当前状态只依赖前几个状态,可用滚动变量代替整个数组。

  • 例如:斐波那契数列只需 a, b, c 三个变量。


动态规划的两种实现方式:

方式 描述 特点
自底向上(迭代) 从最小的子问题开始,逐步构建到原问题 无递归开销,效率高,常用
自顶向下(递归+记忆化) 从原问题出发,递归分解,用哈希表/数组缓存结果 思路直观,但有函数调用开销

经典 DP 问题类型(体现设计思想):

  • 线性 DP:最大子数组和、打家劫舍

  • 区间 DP:最长回文子串、矩阵链乘

  • 背包 DP:0-1 背包、完全背包

  • 树形 DP:二叉树最大路径和

  • 状态机 DP:股票买卖问题


关键总结(一句话):

动态规划 = 最优子结构 + 重叠子问题 + 状态定义 + 状态转移 + 初始条件 + 计算顺序

简单理解一下

动态规划(Dynamic Programming,简称 DP)是一种解决复杂问题的聪明办法把大问题拆成小问题,先解决小问题,再用小问题的答案一步步推出大问题的答案


核心思想(3句话):

  1. 分阶段:把问题分成一步步(比如从第1天到第n天)。

  2. 记答案:把每一步的结果存下来(避免重复算)。

  3. 推着走:后面的答案 = 前面的答案 + 当前选择。


举个简单例子:

爬楼梯:每次能爬 1 或 2 阶,问到第 5 阶有几种方法?

  • 到第1阶:1种

  • 到第2阶:2种(1+1 或 直接2)

  • 到第3阶:= 到第2阶的方法 + 到第1阶的方法 = 2 + 1 = 3

  • 到第4阶:= 第3阶 + 第2阶 = 3 + 2 = 5

  • 到第5阶:= 第4阶 + 第3阶 = 5 + 3 = 8

每一步都用前面的结果,不用从头算!


动态规划的两个条件:

  1. 有重复的小问题(比如算第5阶时,第3阶被用了好多次)

  2. 大问题的最优解 = 小问题的最优解组合起来


一句话总结:

动态规划 = 记住已经算过的,别重复干傻事,从小问题一步步推出大答案

这是解决此问题的标准解法。核心思想是:如果前面的子数组和变成了负数,那就果断丢弃,从当前元素重新开始计算。

  • 思路:
    • 我们维护两个变量:
      • current_sum:以当前元素结尾的连续子数组的最大和。
      • max_sum:全局最大的子数组和。
    • 对于数组中的每一个数 num,我们需要决定是将它加入之前的子数组,还是把它作为新子数组的开头。
      • 如果 current_sum 是负数,加上它只会让结果更小,不如直接从 num 开始。
      • 如果 current_sum 是正数,加上 num 可能会更大,那就加上。
bash 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        // 初始化:假设第一个元素就是最大值
        int current_sum = nums[0];
        int max_sum = nums[0];

        // 从第二个元素开始遍历
        for (int i = 1; i < nums.length; i++) {
            // 核心逻辑:
            // 如果 current_sum < 0,抛弃它,从 nums[i] 重新开始
            // 如果 current_sum >= 0,保留它,加上 nums[i]
            current_sum = Math.max(nums[i], current_sum + nums[i]);
            
            // 更新全局最大值
            max_sum = Math.max(max_sum, current_sum);
        }
        
        return max_sum;
    }
}
相关推荐
weixin_5134499620 小时前
PCA、SVD 、 ICP 、kd-tree算法的简单整理总结
c++·人工智能·学习·算法·机器人
code_pgf20 小时前
Qwen2.5-VL 算法解析
人工智能·深度学习·算法·transformer
Code-keys20 小时前
Android Codec2 Filter 算法模块开发指南
android·算法·音视频·视频编解码
无忧智库20 小时前
低空经济新基建:构建低空飞行大数据中心与行业应用算法工厂的全景式蓝图(WORD)
算法
闻缺陷则喜何志丹21 小时前
【背包 组合】P7552 [COCI 2020/2021 #6] Anagramistica|普及+
c++·算法·背包·洛谷·组合
锅挤1 天前
数据结构复习(第五章):树与二叉树
数据结构
小章UPUP1 天前
2026年第十六届MathorCup数学应用挑战赛D题国奖思路
算法
hssfscv1 天前
软件设计师下午试题四——C语言(N皇后问题、分治、动态规划)
c语言·算法·动态规划
lolo大魔王1 天前
Go语言的反射机制
开发语言·后端·算法·golang
白羊by1 天前
Softmax 激活函数详解:从数学原理到应用场景
网络·人工智能·深度学习·算法·损失函数