Max Sub-array (122A)
Problem Statement
Question. Given a 1-dimensional array, find a contiguous sub-array with the largest sum
A[1...N]: List<number>- the array we select from
Dividing the problem
The maximum sub-array can show up in 3 places:
- The left half of A
- The right half of A
- The middle section of A
The left half and right half does not overlap. Overlap is handled by the middle section.
Base Cases
There are 2 base cases:
- A is empty, so we return 0 for the sum of nothing.
- A has exactly 1 element, so we return that element A[1]
Recursive Cases
To avoid passing the main array around on the stack, we can use the 2 pointer approach with low and high pointers. The recursive calls will look like:
function MaxSubarray():
mid = floor((low + high) / 2)
leftSum = MaxSubarray(low, mid)
rightSum = MaxSubarray(mid + 1, high)
middleSum = MaxMiddleSum(low, mid, high)
where the 2 recursive calls correspond to the left and right half of A.
The Max Middle Sum
The name is kinda misleading, but we want to consider this:
Question. What contiguous sub-array, that might contain the middle element, gives us the maximum sum?
So we check both ways. Take the element if it keeps the array contiguous AND increases the sum.
-
Check from
mid - 1tolow// Inside MaxMiddleSum // Increases only when currLeftSum is better bestLeftSum = -Infinity // Always increases bc the sub-array need to be contiguous currLeftSum = 0 // for loop must go this direction // because the max middle sum could contain both left and right for i = mid - 1 to low: currLeftSum += A[i] if currLeftSum > bestLeftSum: bestLeftSum = currLeftSumExample. Left Half
Selecting...Done selecting,sum = 4

-
Then check from
midtohigh// Inside MaxMiddleSum bestRightSum = -Infinity currRightSum = 0 for i = mid to high: currRightSum += A[i] if currRightSum > bestRightSum: bestRightSum = currRightSumExample. Right Half
Selecting...Done selecting,sum = 3

-
The best middle sum could also involve both the left and right half, for example if all elements are positive. So we take the
max(...)of all:// Inside MaxMiddleSum return max(bestLeftSum + bestRightSum, bestLeftSum, bestRightSum)
Combining the Results
Now we know what’s max in left, right, and middle, we just take the max.
// Inside MaxSubarray
return max(leftSum, rightRum, middleSum)
Pseudocode
function MaxMiddleSum(A[low...high], mid) -> number:
bestLeftSum = -Infinity
currLeftSum = 0
for i = mid - 1 to low:
currLeftSum += A[i]
if currLeftSum > bestLeftSum:
bestLeftSum = currSum
bestRightSum = -Infinity
currRightSum = 0
for i = mid to high:
currRightSum += A[i]
if currRightSum > bestRightSum:
bestRightSum = currRightSum
return max(
bestLeftSum + bestRightSum,
bestLeftSum,
bestRightSum
)
function MaxSubarray(A[low...high]) -> number:
if A is empty:
return 0
if low == high:
return A[1]
mid = floor((low + high) / 2)
leftSum = MaxSubarray(A[low...mid])
rightSum = MaxSubarray(A[mid + 1...high])
middleSum = MaxMiddleSum(A[low...high], mid)
return max(leftSum, rightSum, middleSum)
Python: Max Subarray
Go faster: Max Subarray: Kadane’s Algorithm (WIP)