我有一个给定的数组[-2 -3 4 -1 -2 1 5 -3]
,所以最大的和为7
(从第3个索引到第7个索引的数字)。这个数组只是一个简单的例子,程序应该是用户输入元素和数组的长度。
我的问题是,如何确定哪个总和最大?
我从所有数字中创建了一个总和,并且仅创建了一个正数,但是这个正和会很大,但是由于“ IF语句”,在第三个索引之后我没有使用-1
和-2
“所以我的总和是10,解决方案不好。
答案 0 :(得分:1)
我假设您的问题是要找到具有最大和的连续子数组(至少包含一个数字)。否则,问题很简单,因为您只需选择所有正数即可。
有3种解决方案比O(N ^ 2)蛮力解决方案好。 N是输入数组的长度。
由于子数组至少包含一个数字,因此我们知道只有N个可能的候选:子数组以A [0],A [1] ... A [N-1]结尾 对于以A [i]结尾的子数组,我们具有以下最佳子结构: maxSum [i] = {maxSum [i-1] + A [i],A [i]}的最大值;
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
在遍历整个数组时保持最小sum变量。访问输入数组中的每个数字时,请更新前缀和变量currSum。然后更新以下代码中显示的最大和最小。
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
将原始问题分为两个子问题,然后使用以下公式递归应用此原理。
让A [0,.... midIdx]为A的左半部分,A [midIdx + 1,..... A.length-1]为A的右半部分。leftSumMax是A的答案左子问题rightSumMax是右子问题的答案。
最终答案将是以下3个之一: 1.仅使用左半边的数字(由左子问题解决) 2.仅使用右半部分的数字(由右子问题解决) 3.使用左右两半的数字(以O(n)时间求解)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}
答案 1 :(得分:0)
尝试一下:
i
。sum
的总和,最后一个偏移量为j
。如果此总和大于您当前的最佳总和,它将变为当前最佳总和,其偏移量为i
至j
。sum
,请从该偏移量开始一个新的和,否则继续当前的和。到达数组末尾时停止此操作。找到了最佳的正和。
如果找不到正值,请找到最小的负值,这一项将是您的最佳非平凡值。