【普通数组】【中等】最大子数组和
2026/8/21 20:42:16 网站建设 项目流程

题目

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

提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

方法一:暴力求解

枚举所有子数组,然后计算最大值。子数组数量O(n²),计算和O(n),总复杂度O(n³)

方法二:前缀和

定义 preSum[i] 表示前 i 个元素的和,那么一个区间 [i,j] 的和为 preSum[j]-preSum[i-1]

publicstaticintmaxSubArray(int[]nums){intmax=Integer.MIN_VALUE;intminPrefixSum=Integer.MIN_VALUE;intsum=0;//前缀和数组int[]prefixSum=newint[nums.length+1];prefixSum[0]=0;minPrefixSum=prefixSum[0];for(inti=0;i<nums.length;i++){prefixSum[i+1]=prefixSum[i]+nums[i];//保存之前前缀和的最小值minPrefixSum=Math.min(minPrefixSum,prefixSum[i]);//当前前缀和与最小前缀和的差值sum=prefixSum[i+1]-minPrefixSum;max=Math.max(max,sum);}returnmax;}

注意不能是minPrefixSum = Math.min(minPrefixSum, prefixSum[i+1]);,minPrefixSum 应该保存当前位置之前的最小前缀和,否则如果是数组 [-1] 则会出现 (-1) - (-1) 的情况

方法三:动态规划

对于每个数字:需要考虑当前这个数字加入之前的连续子数组,还是重新开始,例如 nums=[-2,1,-3,4]到4的时候,前面的最大连续和为-2+1-3=-4如果加入-4+4=0但是直接从4开始:4更大。所以需要判断之前的贡献有没有价值。

  • 每一个点处判断max(仅当前值,前面连续的最大值+当前值)
publicstaticintmaxSubArray(int[]nums){int[]dp=newint[nums.length];dp[0]=nums[0];intmax=dp[0];for(inti=1;i<nums.length;i++){dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);max=Math.max(max,dp[i]);}returnmax;}

方法四:分治法

数组 [-2,1,-3,4,-1,2,1,-5,4] 中间切开分为 [-2,1,-3,4] 和 [-1,2,1,-5,4],那么最大子数组只有三种情况:

  • 完全在左边
  • 完全在右边
  • 跨越中间,也就是左边最大后缀 + 右边最大前缀。
    • 左边的最大后缀:就从最后一个数字开始依次计算,取最大值
    • 右边最大前缀:从第一个数字开始以此计算,取最大值
  • 最后依次递归合并

publicstaticintdivide(int[]nums,intleft,intright){if(left==right){returnnums[left];}intmid=(left+right)/2;intleftmax=divide(nums,left,mid);intrightmax=divide(nums,mid+1,right);intcrossmax=maxCross(nums,left,mid,right);returnMath.max(Math.max(leftmax,rightmax),crossmax);}publicstaticintmaxCross(int[]nums,intleft,intmid,intright){//左边最大后缀intleftmax=nums[mid];intsum=0;for(inti=mid;i>=left;i--){sum+=nums[i];leftmax=Math.max(leftmax,sum);}//右遍最大前缀intrightmax=nums[mid+1];sum=0;for(inti=mid+1;i<=right;i++){sum+=nums[i];rightmax=Math.max(rightmax,sum);}returnleftmax+rightmax;}publicstaticintmaxSubArray(int[]nums){returndivide(nums,0,nums.length-1);}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询