#
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 - 1
tolow
// 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 = currLeftSum
Example. Left Half
Selecting...Done selecting,sum = 4
Then check from
mid
tohigh
// Inside MaxMiddleSum bestRightSum = -Infinity currRightSum = 0 for i = mid to high: currRightSum += A[i] if currRightSum > bestRightSum: bestRightSum = currRightSum
Example. 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)