Optimizing performance for max sum in list-of-lists for original list

Question:

I am working on my python, doing codewars. The description is as follows:


The maximum sum subarray problem consists in finding the maximum sum of a contiguous subsequence in an array or list of integers:

max_sequence([-2, 1, -3, 4, -1, 2, 1, -5, 4])
should be 6: [4, -1, 2, 1]

Easy case is when the list is made up of only positive numbers and the maximum sum is the sum of the whole array. If the list is made up of only negative numbers, return 0 instead.

Empty list is considered to have zero greatest sum. Note that the empty list or array is also a valid sublist/subarray.


Great! Done! here’s my code, which passes the tests:

def max_sequence(arr):
    sums = []
    lists = [[]]
    for i in range(len(arr) + 1):
        for j in range(i):
            lists.append(arr[j: i])
    for i in lists:
        sums.append(sum(i))
    return max(sums)

However, for submission, codewars requires you to pass a larger battery of tests, and the tests timeout for larger sets.

In the discussion, many people have the same problem as me. One answer in particular gets to the root of the question, which is what i’m asking here (see the comment below):

Your code is not optmised to work with longer arrays, whilst your code likely works, it takes too long to solve the harder problems so times out. This questions is as much an optimisation problem as any. So you need to find a way to optimise your solution

That is very true for me! What am i doing "wrong" in this data structure, and how can i improve it? My current guesses for the most expensive computations are:

  1. loop within loop (for i in range…. for j in range i)
  2. lists.append(arr[j:i])

Any advice? How to improve performance here? I am thinking as much about general data structures and learning as i am about solving this specific question. Thank you!

Asked By: user11781

||

Answers:

Reference: https://en.wikipedia.org/wiki/Maximum_subarray_problem#Kadane’s_algorithm

You can use Kadane’s Algorithm. The idea is that keep adding elements to curr and get the maximum of curr and num. When the sum of the subarray is positive, it keeps going. When the sum of the subarray is negative, it gives up the negative subarray.

You can consider this example with the following code: [-1,1000,-2]. Initially, curr = -1. Since it is negative, curr gives up -1 and gets the value of 1000. Finally, since 1000 is greater than 998, it returns 1000 as the answer.

This only has a time complexity of O(n) instead of the brute force approach that has an O(n^3).

def max_sequence(arr):
    if not arr or max(arr) < 0: 
        return 0

    curr = max_sub = arr[0]

    for num in arr[1:]:
        curr = max(num, curr + num)
        max_sub = max(max_sub, curr)

    return max_sub
Answered By: コリン

Similar idea with earlier post, but it tries to bail out earlier when hitting edge cases: (it’s still achieved O(n) )


def maxSequence(arr):
    if not arr: return 0              # check if it's empty list
    if max(arr) < 0: return 0         # check if all negatives

    maxx,curr= 0, 0

    for x in arr:
        curr += x
        if curr < 0: 
           curr = 0
        if curr> maxx: 
            maxx = curr
    return maxx
Answered By: Daniel Hao