普通数组----最大子数组和

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

<<Git>><<MySQL>>

🌟心向往之行必能至

一、题目背景

LeetCode 53 题「最大子数组和」是算法面试中的经典问题,属于动态规划与前缀和的典型应用。题目要求在给定整数数组中,找到一个连续子数组(最少包含一个元素),使其和最大并返回该值。

例如:

  • 输入 nums = [-2,1,-3,4,-1,2,1,-5,4],输出 6(对应子数组 [4,-1,2,1])。
  • 输入 nums = [5,4,-1,7,8],输出 23(对应子数组 [5,4,-1,7,8])。

这道题不仅考察算法思维,还能帮助理解「前缀和」「动态规划」等核心概念,是大厂面试的高频考点。

二、核心思路:前缀和 + 最小前缀和

1. 前缀和的定义

对于数组 nums,定义前缀和数组 sum,其中 sum[i] 表示从 nums[0]nums[i] 的累加和:

sum[i]=nums[0]+nums[1]+⋯+nums[i]

那么,子数组 nums[j+1 ... i] 的和可以表示为:

sum[i]−sum[j]

我们的目标是找到 j < i,使得 sum[i] - sum[j] 最大。

2. 转化问题:找最小前缀和

对于每个 i,要让 sum[i] - sum[j] 最大,等价于找到最小的 sum[j](其中 j < i

因此,我们可以维护两个变量:

  • sum:当前的前缀和(sum[i])。
  • min_sum:遍历到当前位置时,最小的前缀和(min{sum[0], sum[1], ..., sum[i-1]})。

每遍历一个元素,我们先更新当前前缀和 sum,然后计算 sum - min_sum(即当前子数组的最大可能和),并维护全局最大值 Max。最后更新 min_sum 为当前最小的前缀和。

3. 初始值的关键设置

  • sum 初始化为 0,表示前缀和从空数组开始累加。
  • min_sum 初始化为 0,对应 sum[-1] = 0(空数组的前缀和),确保第一个元素也能正确计算。
  • Max 初始化为 INT_MIN,处理数组全为负数的情况(例如 nums = [-5,-3,-2],最大子数组和为 -2)。

三、代码实现(C++)

cpp

运行

复制代码
#include <vector>
#include <climits>
using namespace std;

class Solution {
public:
    // 子数组可以看成子数组最右边的前缀和减去它前面的最小前缀和
    int maxSubArray(vector<int>& nums) {
        int sum = 0;
        int Max = INT_MIN;
        int min_sum = 0;
        for (int i = 0; i < nums.size(); ++i) {
            sum += nums[i];
            Max = max(Max, sum - min_sum); // 计算当前子数组的最大和
            min_sum = min(min_sum, sum);   // 更新最小前缀和
        }
        return Max;
    }
};

四、代码逐行解析

  1. 变量初始化

    • sum = 0:当前前缀和,初始为空数组的和。
    • Max = INT_MIN:全局最大子数组和,初始为最小整数,确保能正确更新负数情况。
    • min_sum = 0:最小前缀和,初始为空数组的和。
  2. 遍历数组

    • sum += nums[i]:累加当前元素,更新前缀和。
    • Max = max(Max, sum - min_sum):计算以当前元素结尾的子数组的最大和(当前前缀和减去之前的最小前缀和),并更新全局最大值。
    • min_sum = min(min_sum, sum):更新最小前缀和,确保后续计算能用到更小的前缀和。
  3. 返回结果 :遍历结束后,Max 即为整个数组的最大子数组和。

五、示例验证(以 nums = [-2,1,-3,4,-1,2,1,-5,4] 为例)

索引 i nums[i] sum(前缀和) sum - min_sum Max min_sum
0 -2 -2 -2 - 0 = -2 -2 min(0,-2)=-2
1 1 -1 -1 - (-2) = 1 1 min(-2,-1)=-2
2 -3 -4 -4 - (-2) = -2 1 min(-2,-4)=-4
3 4 0 0 - (-4) = 4 4 min(-4,0)=-4
4 -1 -1 -1 - (-4) = 3 4 min(-4,-1)=-4
5 2 1 1 - (-4) = 5 5 min(-4,1)=-4
6 1 2 2 - (-4) = 6 6 min(-4,2)=-4
7 -5 -3 -3 - (-4) = 1 6 min(-4,-3)=-4
8 4 1 1 - (-4) = 5 6 min(-4,1)=-4

最终,Max = 6,与示例输出一致。

六、复杂度分析

  • 时间复杂度O(n),仅需遍历数组一次,每个元素的操作都是常数时间。
  • 空间复杂度O(1),仅使用了常数个变量,未额外开辟数组空间。

七、解法对比

解法 时间复杂度 空间复杂度 适用场景
前缀和 + 最小前缀和 O(n) O(1) 追求时间、空间效率最优
Kadane 算法(动态规划) O(n) O(1) 直观理解「当前子数组和是否延续」
分治法 O(n log n) O(log n) 理解分治思想,适合教学场景

前缀和 + 最小前缀和的解法与 Kadane 算法效率相同,但思路更偏向数学推导,适合从前缀和的角度理解问题。

八、总结

LeetCode 53 题的核心是将「最大子数组和」转化为「前缀和的差值最大化」问题,通过维护最小前缀和,在一次遍历中完成计算,时间和空间复杂度均为最优。这种思路不仅能解决本题,还可拓展到类似的子数组和问题(如返回子数组的起始 / 结束索引)。

相关推荐
2302_813806222 小时前
【嵌入式修炼:数据结构篇】——单向链表的排序
数据结构·链表·排序算法
五度易链-区域产业数字化管理平台2 小时前
「五度易链」行业标准信息数据库简介
大数据·数据库
数研小生2 小时前
关键词搜索京东列表API技术对接指南
大数据·数据库·爬虫
星辰_mya2 小时前
Elasticsearch之下
大数据·elasticsearch·搜索引擎
52Hz1182 小时前
力扣230.二叉搜索树中第k小的元素、199.二叉树的右视图、114.二叉树展开为链表
python·算法·leetcode
苦藤新鸡2 小时前
56.组合总数
数据结构·算法·leetcode
LiLiYuan.2 小时前
【Cursor 中找不到LeetCode 插件解决办法】
算法·leetcode·职场和发展
Charlie_lll2 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode