5 Best Ways to Solve the Maximum Subarray Problem Using Kadane’s Algorithm in Python

💡 Problem Formulation: The maximum subarray problem involves finding the contiguous subarray within a one-dimensional array of numbers which has the largest sum. For instance, given the array [-2, 1, -3, 4, -1, 2, 1, -5, 4], the contiguous subarray with the largest sum is [4, -1, 2, 1], with a sum of 6.

Method 1: Basic Kadane’s Algorithm

Kadane’s Algorithm offers an efficient way to solve the maximum subarray problem with a linear time complexity of O(n). It involves iterating through the array while maintaining two variables to store the maximum sum found so far and the current sum. The current sum resets to zero when it becomes negative, ensuring only positive contributions to the max sum.

Here’s an example:

def max_subarray(numbers):
    max_sum = current_sum = numbers[0]
    for number in numbers[1:]:
        current_sum = max(number, current_sum + number)
        max_sum = max(max_sum, current_sum)
    return max_sum

numbers = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray(numbers))

Output:

6

This code initializes max_sum and current_sum with the first element of the array. Then, for each other element, it determines whether to add the element to the existing current_sum or start anew. The max_sum is updated accordingly. The function returns the maximum sum found.

Method 2: Kadane’s Algorithm with Start and End Indices

This variant of Kadane’s Algorithm also finds the starting and ending indices of the maximum subarray, in addition to the sum. As we track the maximum sum, we also keep track of the indices by resetting the start index when the current sum is reset.

Here’s an example:

def max_subarray_indices(numbers):
    max_sum = current_sum = numbers[0]
    start = end = 0
    temp_start = 0
    
    for i, number in enumerate(numbers[1:], 1):
        if current_sum  max_sum:
            max_sum = current_sum
            start = temp_start
            end = i
            
    return max_sum, start, end

numbers = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray_indices(numbers))

Output:

(6, 3, 6)

The function max_subarray_indices not only computes the maximum sum but also returns the starting and ending indices of the maximum subarray. The temporary start variable temp_start is updated when the current sum is reset.

Method 3: Kadane’s Algorithm with Modifications for All Negative Numbers

Standard Kadane’s Algorithm fails when all numbers in the array are negative. This method modifies the algorithm to handle such cases correctly, ensuring that we always return the maximum negative number if no positive sum subarray exists.

Here’s an example:

def max_subarray_all_negatives(numbers):
    max_sum = current_sum = numbers[0]
    for number in numbers[1:]:
        current_sum = max(number, current_sum + number)
        max_sum = max(max_sum, current_sum)
        if max_sum < 0:
            max_sum = max(max_sum, number)
    return max_sum

numbers = [-8, -3, -6, -2, -5, -4]
print(max_subarray_all_negatives(numbers))

Output:

-2

This code snippet ensures that if the array consists of all negative numbers, the maximum number is returned instead of zero or a positive sum that doesn’t exist. It does this by checking if the max_sum remains negative and updating it with the maximum single element if needed.

Method 4: Optimized Kadane’s Algorithm to Return Subarray

This optimization returns not just the maximum sum but the actual subarray that constitutes this sum. It builds upon the previous methods but includes an additional step to extract the subarray based on the start and end indices.

Here’s an example:

def kadane_subarray(numbers):
    max_sum = current_sum = numbers[0]
    start = end = 0
    temp_start = 0
    for i, number in enumerate(numbers[1:], 1):
        if current_sum  max_sum:
            max_sum = current_sum
            start = temp_start
            end = i
    return numbers[start:end+1], max_sum

numbers = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(kadane_subarray(numbers))

Output:

([4, -1, 2, 1], 6)

The kadane_subarray function implements Kadane’s Algorithm while keeping track of the indices, and finally returns the subarray between the start and end points. This allows users to see the actual subarray that adds up to the maximum sum.

Bonus One-Liner Method 5: Kadane’s Algorithm in a Lamba Function

The power of Python’s lambdas can be used to condense the Kadane’s Algorithm into a single line of code. This method is more of a novelty and for those who appreciate the concise expression of logic.

Here’s an example:

from functools import reduce

numbers = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
max_subarray_one_liner = reduce(lambda r, x: max(r, r + x, x), numbers, numbers[0])
print(max_subarray_one_liner)

Output:

6

The one-liner uses functools.reduce to apply a lambda function that computes Kadane’s logic across the array. r represents the running sum, and x is the current element as reduce iterates over the array.

Summary/Discussion

Method 1: Basic Kadane’s Algorithm. Strengths: Simple and efficient. Weaknesses: Doesn’t provide subarray indices.
Method 2: Kadane with Indices. Strengths: Finds indices which can be useful. Weaknesses: Slightly more complex.
Method 3: Handle All Negative Arrays. Strengths: Works with arrays containing all negative numbers. Weaknesses: Unnecessary computation for mixed arrays.
Method 4: Return Actual Subarray. Strengths: Returns subarray, not just sum. Weaknesses: Additional storage for the subarray.
Method 5: Lambda One-Liner. Strengths: Extremely concise. Weaknesses: Less readable, harder to understand and maintain.