最大总和子列表?

时间:2013-02-25 08:27:44

标签: python algorithm

我对这个问题感到困惑。

  

写入函数mssl()(最小和子列表),将列表作为输入   整数。然后计算并返回最大总和的总和   输入列表的子列表。最大总和子列表是子列表   输入列表的(切片),其条目总和最大。空的   子列表定义为总和0.例如,最大总和子列表   列表[4, -2, -8, 5, -2, 7, 7, 2, -6, 5][5, -2, 7, 7, 2]   其条目总和为19

如果我要使用此功能,它应返回类似于

的内容
>>> l = [4, -2, -8, 5, -2, 7, 7, 2, -6, 5]
>>> mssl(l)
19
>>> mssl([3,4,5])
12
>>> mssl([-2,-3,-5])
0

我该怎么做?

这是我目前的尝试,但它不会产生预期的结果:

def mssl(x):
    ' list ==> int '
    res = 0
    for a in x:
        if a >= 0:
            res = sum(x)
        return res
    else:
        return 0

13 个答案:

答案 0 :(得分:54)

使用动态编程实际上是一个非常优雅,非常有效的解决方案。它需要 O(1)空间 O(n)时间 - 这不能被击败!

A定义为输入数组(零索引),将B[i]定义为所有子结尾的最大总和,但不包括位置i(即所有子列表{ {1}})。因此,A[j:i]B[0] = 0B[1] = max(B[0]+A[0], 0)B[2] = max(B[1]+A[1], 0)等等。然后,显然,解决方案仅由B[3] = max(B[2]+A[2], 0)提供。

由于每个max(B[0], ..., B[n])值仅取决于之前的B,我们可以避免存储整个B数组,从而为我们提供O(1)空间保证。

通过这种方法,B简化为一个非常简单的循环:

mssl

演示:

def mssl(l):
    best = cur = 0
    for i in l:
        cur = max(cur + i, 0)
        best = max(best, cur)
    return best

如果你想要开始和结束切片索引,你需要跟踪更多的信息(注意这仍然是O(1)空间和O(n)时间,它只是有点毛茸茸):< / p>

>>> mssl([3,4,5])
12
>>> mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
19
>>> mssl([-2,-3,-5])
0

这会返回一个元组def mssl(l): best = cur = 0 curi = starti = besti = 0 for ind, i in enumerate(l): if cur+i > 0: cur += i else: # reset start position cur, curi = 0, ind+1 if cur > best: starti, besti, best = curi, ind+1, cur return starti, besti, best ,使(a, b, c)sum(l[a:b]) == c最大:

c

答案 1 :(得分:7)

这是the maximum sub-array problem。 Kadane的算法可以在O(n)时间和O(1)空间中解决它,它如下:

def mssl(x):
    max_ending_here = max_so_far = 0
    for a in x:
        max_ending_here = max(0, max_ending_here + a)
        max_so_far = max(max_so_far, max_ending_here)
    return max_so_far

答案 2 :(得分:4)

根据问题,万一,如果列表中的所有元素都是否定的,它应该返回最大总和为&#39; ZERO&#39;

相反,如果您希望输出为子阵列的最大值(负数),则以下代码将有所帮助:

In [21]: def mssl(l):
...:     best = cur = l[0]
...:     for i in range(len(l)):
...:         cur = max(cur + l[i], l[i])
...:         best = max(best, cur)
...:     return best

的示例:

In [23]: mssl([-6, -44, -5, -4, -9, -11, -3, -99])
Out[23]: -3
In [24]: mssl([-51, -23, -8, -2, -6])
Out[24]: -2

正数和负数

In [30]: mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
Out[30]: 19

答案 3 :(得分:3)

因此,如果您了解子列表是什么(或切片,可以假设它是相同的),则切片由起始索引和结束索引定义。

所以也许你可以尝试迭代所有可能的开始和结束索引并计算相应的总和,然后返回最大值。

提示:起始索引可以从0到len(given_list)-1不等。结束索引可以从start_indexlen(given_list)-1。您可以使用嵌套的for循环来检查所有可能的组合。

答案 4 :(得分:3)

这是Java中的一个实现,使用Kadane的算法,它打印最大总和的索引。实现需要O(n)时间和O(1)空间。

public static void maxSumIndexes(int[] a) {

    int size = a.length;
    if(size == 0) return;

    int maxAtIndex = a[0], max = a[0];
    int bAtIndex = 0;
    int b = 0, e = 0;

    for(int i = 1; i < size; i++) {
        maxAtIndex = Math.max(a[i], a[i] + maxAtIndex);
        if(maxAtIndex == a[i])
            bAtIndex = i;

        max = Math.max(max, maxAtIndex);
        if(max == maxAtIndex) {
            e = i;
            b = (b != bAtIndex)? bAtIndex : b;
        }
    }

    System.out.println(b);
    System.out.println(e);
}

答案 5 :(得分:2)

简单的解决方案是遍历列表,只是尝试添加切片直到找到最佳切片。这里我还包括返回实际子列表的选项,默认情况下为False。我为此目的使用了defaultdict,因为它比查找更简单。

from collections import defaultdict

def mssl(lst, return_sublist=False):
    d = defaultdict(list)
    for i in range(len(lst)+1):
        for j in range(len(lst)+1):
            d[sum(lst[i:j])].append(lst[i:j])
    key = max(d.keys())
    if return_sublist:
        return (key, d[key])
    return key

print mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
19
print mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5], True)
(19, [[5, -2, 7, 7, 2]])

奖金:列表理解方法:

def _mssl(lst):
    return max( sum( lst[i:j] ) for i in xrange(len(lst)+1) for j in xrange(i, len(lst)+1) )

答案 6 :(得分:1)

它要求你选择一个较小的分段,以便较小的分段的总和是最大的。

如果列表全部为正[1 2 3],那么具有最大总和的子部分只是整个列表[1 2 3]的总和,即6。

如果列表全部为负[-1 -2 -3],则具有最大总和的子部分为[],其总和为0. {/ p>

然而,如果列表有一些积极的和一些否定的决定更难

[1 2 3 -100 3 4 5]您应该看到[3 4 5]并返回12

[1 2 3 -2 3 4 5]你应该全部使用它并返回16

答案 7 :(得分:1)

我假设这是在数组中找到产生最大总和的子序列的问题。我在搜索最大总和SUBSET问题时遇到了这个问题。

此问题的java实现:

public static int maximumSumSubSequence(int[] array) {

    if (null == array) {
        return -1;
    }

    int maxSum = Integer.MIN_VALUE;
    int startIndexFinal = 0;
    int endIndexFinal = 0;
    int currentSum = 0;
    int startIndexCurrent = 0;

    for (int i = 0; i < array.length; i++) {
        currentSum += array[i];

        if (currentSum > maxSum) {
            maxSum = currentSum;
            endIndexFinal = i;
            startIndexFinal = startIndexCurrent;
        }
        if (currentSum <= 0) {
            currentSum = 0;
            startIndexCurrent = i + 1;
        }
    }
    System.out.println("startIndex: " + startIndexFinal + " endIndex: " + endIndexFinal);
    return maxSum;
}

答案 8 :(得分:0)

这种区别可能对OP来说并不重要,OP似乎只是试图理解如何解决问题,但我认为值得一提:

此处的其他解决方案涉及重复总结列表的所有子部分。我们可以通过使用动态编程来避免这些重复的总和,因为当然如果我们已经知道从ij的总和,我们不需要再次添加它们来从{{获得总和1}}到i

即,制作部分和的2d数组,以便j+1。类似的东西(使用字典因为它更容易索引;一个numpy数组同样容易和高效):

partsum[i, j] == sum(lst[i:j])

这需要O(n ^ 2)时间和内存,而不是O(n ^ 3)时间和O(1)内存用于Lev / Inbar的方法(如果没有像Inbar的第一个代码示例那样狡猾地实现)。 p>

答案 9 :(得分:0)

这个post引入了三种方法来查找数组的最大子数组。

  • 蛮力(O(n * n))
  • 分而治之(O(nlgn))
  • Kadane的算法(O(n))

其中,最快的是Kadane算法,其时间复杂度为O(n)。

答案 10 :(得分:0)

如果有人正在寻找更长版本的代码,那么它就是:

def mesl(lst):
    sub_sum = list()
    row_sum = list()
    for i in range(len(lst)):
        sub_sum = list()
        sub_sum.append(lst[i])
        k = 1
        for j in range(i+1,len(lst)):
            sub_sum.append(sub_sum[k-1] + lst[j])
            k+=1
        row_sum.append(max(sub_sum))      
    sum = max(row_sum)
    if  sum < 0:
        sum = 0
    return sum

答案 11 :(得分:0)

我正在介绍一种基于动态编程的方法。主要思想是,当我们遍历数组时,在当前的总和值中添加一个新元素应该会增加总和的值,或者继续使用当前的元素而忘记旧的总和值。

要容纳带有负值的数组,请使用数组的第一个元素实例化变量。

def maxSumSubArr(arr):
    cur_sum = best_sum = arr[0]
    for i in range(1, len(arr)):
        cur_sum = max(arr[i], cur_sum+arr[i])
        best_sum = max(best_sum, cur_sum)
    return best_sum

该方法的运行时间为O(n),空间复杂度为O(1)。

如果在所有元素都不为正的情况下希望输出为零,则将cur_sum和best_sum变量实例化为0,然后从第一个元素而不是第二个元素进行迭代。

答案 12 :(得分:0)

这是javascript中最大子数组问题的最短和最佳解决方案:

app.get('/', (req, res) => {
    // render your index.handblars
})

app.get('/contact', (req, res) => {
    // render your contact.handlebars
})