我将如何找到具有以下条件的数组的最大总和?
Posted
技术标签:
【中文标题】我将如何找到具有以下条件的数组的最大总和?【英文标题】:How would I go about finding the maximum sum of an array with the following conditions? 【发布时间】:2021-09-13 22:16:13 【问题描述】:如何在以下条件下找到数组的最大和:
求和必须是连续的。 如果存在任何 0,则认为是“中断” 数组总和中的值不能大于最小值示例
1 0 1 0 0 = 1
2 0 2 1 1 = 3, why? [2 1 1] -> 1 + 1 + 1
3 1 3 2 2 = 6, why? [3 2 2] -> 2 + 2 + 2
4 0 0 3 0 = 4
我试图考虑一种自下而上的实现方式,跟踪迄今为止的最小值 同时跟踪最大总和,但我被卡住了......
【问题讨论】:
【参考方案1】:有效计算给定元素最小的范围:
计算每个元素最小的范围为(i,j)
,不包括i
和j
。然后将该元素作为该范围内的最小值,总和为(j-i-1)*element
。
取所有这些值的最大值。
这也应该注意数组中存在的任何零。
如果你仔细想想,这只是另一种询问直方图形成的最大矩形是多少的方式。
举个例子:[ 3, 1, 3, 2, 2 ]
对于第一个元素 3 :它的最小值范围是 (-1,1),其中 -1 在数组之外,总和是 3*(1-(-1)-1) = 3
对于第二个元素 1 :最小值的范围是 (-1,5) 并且总和是 1*(5-(-1)-1) = 5
....
....
对于第五个元素 2 :最小值的范围是 (1, 5) 并且总和是 2*(5-1-1) = 6
对于所有元素,它是:3 5 3 6 6
最大值为 6。
如何计算范围?
左边界:
对于任何给定的元素,如果它更大,则向左看,然后取其左边界并继续,直到遇到小于当前元素的元素。请注意,您不是逐个元素,而是按“bounds”。这是重要的。
右边界:
你同样向右看,看它是否更大,但继续向右看,直到你碰到一个小于当前元素的元素。
Java 代码如下:
private static int solve(int[] arr)
int n = arr.length;
int[] leftBound = new int[n];
int[] rightBound = new int[n];
leftBound[0] = -1;
rightBound[n-1] = n;
for ( int i = 1; i < n; i++ )
int bound = i-1;
while ( bound >= 0 && arr[bound] >= arr[i] )
bound = leftBound[bound];
leftBound[i] = bound;
for ( int i = n-2; i >= 0; i-- )
int bound = i+1;
while ( bound < n && arr[bound] >= arr[i] )
bound = rightBound[bound];
rightBound[i] = bound;
int res = 0;
for ( int i = 0; i < n; i++ )
res = Math.max( res, (rightBound[i] - leftBound[i] - 1)*arr[i]);
return res;
【讨论】:
这是 O(N^2)? 这是 O(N)。因为跳转/边界只遍历一次。在最坏的情况下,如果必须一直向左移动才能找到一个较小的元素,那么到那时您已经创建了边界,并且后续元素不会再次遍历这些边界。以上是关于我将如何找到具有以下条件的数组的最大总和?的主要内容,如果未能解决你的问题,请参考以下文章