2

Here's a java implementation of Kadane's algorithm to find the sum of a contiguous subarray with the max sum.

    static int maxSum(int[] arr) {
        int maxEndingHere = arr[0];
        int maxGlobal = arr[0];

        for (int i = 1; i < arr.length; i++) {
            maxEndingHere = Math.max(arr[i], maxEndingHere + arr[i]);
            maxGlobal = Math.max(maxGlobal, maxEndingHere);
        }
        return maxGlobal;

    }

This just returns the sum. I would like the actual subarray. It seems like that information is lost, though. I tried updating the start index when the local max got reset and the end index when the global max got updated, but that fails on this case:

        int[] arr = {-57, -10000, -1, -4, -45, -6, -9, -19, -16, -17};

Note there was a similar question here: How to return maximum sub array in Kadane's algorithm?

but as far as I can tell, every answer would fail in cases with a negative sum.

marathon
  • 7,881
  • 17
  • 74
  • 137
  • Re: "every answer would fail in cases with a negative sum": The only way to get a negative sum is if all elements are negative, in which case the maximal nonempty subarray is the one containing the least negative element. So, if nothing else, you can easily handle that case as a separate pass if/when the sum is negative. – ruakh Feb 05 '19 at 02:35

2 Answers2

6

Since you tagged algorithm here is an explanation followed by a python implementation.

This problem is a straightforward extension of the Kadane's algorithm. Kadane's algorithm as follows:

for each item in arr:
    current_max = max(current_max + item, item)
    global_max = global_max(current_max, global_max)

We simply need to record the indices for whenever current and global max are updated:

for each item in arr:

    # updating current max and keeping track current of start and end indices
    current_max = max(current_max + item, item)
    if item is new current_max: set current_start_index to this index
    set current_end_index to this index

    # keep track of global start and end indices
    global_max = max(global_max, current_max)
    if global_max has been updated: 
        set global_start to current_start
        set global_end to current_end

Python implementation:

def maxSum(arr):

  cur_max = glob_max = float('-inf')
  glob_start = glob_end = cur_start = -1

  for index, item in enumerate(arr):

    if item > cur_max + item:
      cur_max = item
      cur_start = index
    else:
      cur_max += item

    if cur_max > glob_max:
      glob_max = cur_max
      glob_start = cur_start
      glob_end = index
  return arr[glob_start:glob_end+1]

Some test cases:

arr = [-57, -10000, -1, -4, -45, -6, -9, -19, -16, -17]
arr = [-1, 2, -1, 20, -4, -5, -6, -9, -19, -16, -17]

Output:

[-1]
[2, -1, 20]

Note that if you want to consider the empty contiguous subarray just add a check at the end - if the global max is less than 0, return an empty array.

Finally some additional code to demonstrate that the algorithm is correct:

def kadane(arr):
  a = b = float('-inf')
  for i in arr:
    a = max(i, a+i)
    b = max(a, b)

  return b

from random import random

for _ in range(10000):
  arr = [random()-0.5 for _ in range(50)]
  assert kadane(arr) == sum(maxSum(arr))

This creates random arrays with positive and negatives and asserts that the sum of the output array is equal to the output of the regular version of kadane's algorithm.

repl.it link with code

Primusa
  • 13,136
  • 3
  • 33
  • 53
0

Heres also implementation in C++, both Kadane (which is actually just dynamic programming approach) and extended Kadane with indices calculation and some comments:

    int maxSubArray(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        
        // total max sum
        int sumMax = nums[0];
        for(int i = 1; i < n; i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new max sum that ends at I
            sumMaxI = max(currSumMaxI, curr);
            
            // calc new total max sum
            sumMax = max(sumMax, sumMaxI);
        }
        
        return sumMax;
    }    
    
    
    int maxSubArray_findBeginEnd(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        // start index for max sum (end index is I)
        int sumMaxIStart = 0;
                
        // total max sum
        int sumMax = nums[0];
        // start and end index for total max sum
        int sumMaxStart = 0;
        int sumMaxEnd = 0;
        for(int i = 1; i < nums.size(); i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new min sum that ends at I and its starting index
            // this part is equal to: sumMaxI = max(currSumMaxI, curr);
            // but additionaly enables to save new start index as well
            if(curr > currSumMaxI)
            {
                sumMaxI = curr;
                sumMaxIStart = i;
            }
            else
                sumMaxI = currSumMaxI;
                 
            // calculate total max sum
            // this part is equal to: sumMax = max(sumMax, sumMaxI);
            if(sumMaxI > sumMax)
            {
                sumMax = sumMaxI;
                sumMaxStart = sumMaxIStart;
                sumMaxEnd = i;
            }
            // this part is to additionaly capture longest subarray among all that have max sum
            // also, of all subarrays with max sum and max len, one with smallest index
            // will be captured
            else if(sumMaxI == sumMax) 
            {
                if(i - sumMaxIStart > sumMaxEnd - sumMaxStart)
                {
                    sumMaxStart = sumMaxIStart;
                    sumMaxEnd = i;
                }
            }
        }
        
        // check validity of start and end indices
        int checkSum = 0;
        for(int i = sumMaxStart; i <= sumMaxEnd; i++)
            checkSum += nums[i];
        assert(checkSum == sumMax); 
        
        // output indices
        cout << "Max subarray indices: [" << sumMaxStart << "," << sumMaxEnd << "]" << endl;
        
        return sumMax;
    }