11、最大子序和

xiaoxiao2025-08-22  81

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 进阶:

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

这道题有点难度 我的这个代码超时了

int max = Integer.MIN_VALUE; int min = 0; for(int i = 0; i < nums.length; i++){ for(int j = i; j < nums.length; j++){ min = 0; for(int k = i; k < j+1; k++){ min += nums[k]; } if(min > max) max = min; } } return max;

将上面的代码进行优化,只用两层循环,改成这样的,就是说外层是对所有元素起点的循环,内层是对所有元素的总和进行求和计算,在进行计算求和的过程中,不断和max进行比较,如果发现其值大于max则更新max的值 代码如下,但是也是刚刚通过了,打败了10%…

int max = Integer.MIN_VALUE; int min = 0; for(int i = 0; i < nums.length; i++){ min = 0; for(int j = i; j < nums.length; j++){ min +=nums[j]; if(max < min){ max = min; } } } return max;

尝试使用递归来进行解决 首先就是最大要么出现在 1、左半部分 2、右半部分 3、包含了中间的元素

public static int maxSubsequenceSum(int[] a, int left, int right) { if(left == right) { //Base case if(a[left] > 0) { return a[left]; } else { return 0; //保证最小值为0 } } int center = (left+right)/2; int maxLeftSum = maxSubsequenceSum(a, left, center); //递归调用,求左部分的最大和 int maxRightSum = maxSubsequenceSum(a, center+1, right);//递归调用,求右部分的最大和 int leftBorderSum = 0, maxLeftBorderSum = 0;//定义左边界子序列的和 for(int i=center; i>=left; i--) {//求左边界的最大和(从右边开始往左求和) leftBorderSum += a[i]; if(leftBorderSum > maxLeftBorderSum) { maxLeftBorderSum = leftBorderSum; } } int rightBorderSum = 0, maxRightBorderSum = 0;//定义右边界子序列的和 for(int i=center+1; i<=right; i++) {//求右边界的最大和(从左边开始往右求和) rightBorderSum += a[i]; if(rightBorderSum > maxRightBorderSum) { maxRightBorderSum = rightBorderSum; } } //选出这三者中的最大值并返回(max3(int a, int b, int c)的实现没有给出) return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum); }

转https://my.oschina.net/itblog/blog/267860 看一下排名靠前的代码,看看别人是怎么想的

首先定义一个长度为nums数组长度的数组subSums 遍历序列的时候对Sum进行累计,如果Sum累积后小于0的话就把Sum重置为下一个数字,每次更新Sum的最大值。最后便能求出最大值。其实这个算法就是把序列分为好几块,每一块满足:对于任意k,前k个数的和不会小于0(小于0就会分裂成两块了),当前i个数的和大于最大值时就进行更新,而最大值的左边界就是该块序列的第一个,右边界是第i个。时间复杂度为O(n),而且可以一边读取一边处理,不需要开辟数组来存,空间也很省

摘自https://blog.csdn.net/samjustin1/article/details/52043369 还需要好好琢磨一下

int subSums = nums[0]; int max = subSums; for (int i=1; i<nums.length; i++) { subSums = subSums > 0 ? subSums + nums[i] : nums[i]; if (subSums > max) { max = subSums; } } return max; return max; } }

动态规划解法 dp做法是很普遍的做法,只要想出状态转移方程就可以很快做出来了。 状态转移方程:sum[i] = max{sum[i-1]+a[i],a[i]}. (sum[i]记录以a[i]为子序列末端的最大连续和。)在dp的过程中便可以更新sum数组的最大值以及两个边界。 其实完全可以不用开数组,累计sum直到sum + a < a,把sum赋值为a,更新最大值就行了。你会发现这跟第4种方法是一样的。。。只是判断条件不一样,一个是sum <= 0一个是sum + a < a。。。(其实是一样的。。。) https://blog.csdn.net/samjustin1/article/details/52043369 代码跟第四种基本一样

转载请注明原文地址: https://www.6miu.com/read-5035144.html

最新回复(0)