我将如何找到具有以下条件的数组的最大总和?

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),不包括ij。然后将该元素作为该范围内的最小值,总和为(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)。因为跳转/边界只遍历一次。在最坏的情况下,如果必须一直向左移动才能找到一个较小的元素,那么到那时您已经创建了边界,并且后续元素不会再次遍历这些边界。

以上是关于我将如何找到具有以下条件的数组的最大总和?的主要内容,如果未能解决你的问题,请参考以下文章

如何找到满足条件的数字的确切数量? [复制]

给定一个数组和一个总和,找到小于总和的最大长度连续子数组

找到总和最大的递增子序列

使用带有扭曲的javascript找到最大总和

在 MySQL 中,如何找到分组在特定列上的 N 个最大值的总和? [复制]

如何找到从多个数组中提取的数字的最小总和?