AlgoMaster Logo

Maximum Subarray

Last Updated: March 22, 2026

medium
4 min read

Understanding the Problem

We need to find a contiguous portion of the array whose elements add up to the largest possible sum. The subarray must contain at least one element, so we can't return 0 for an array of all negatives.

What makes this tricky is that negative numbers can appear anywhere. A subarray like [4, -1, 2, 1] has a sum of 6, which is better than just [4] alone, even though there's a -1 in the middle. So we can't simply skip all negatives. The question becomes: when is it worth absorbing a negative number to reach larger positives later, and when should we cut our losses and start fresh?

That's the key tension in this problem, and each approach handles it differently.

Key Constraints:

  • nums.length up to 10^5 means O(n^2) would mean up to 10^10 operations, which will time out. We need O(n log n) or better.
  • Elements can be negative (-10^4 <= nums[i] <= 10^4), so we can't simply skip negatives or use a sliding window that assumes monotonic growth.
  • The array is guaranteed non-empty (length >= 1), so we always have at least one valid subarray.

Approach 1: Brute Force

Intuition

The most straightforward way is to check every possible subarray and find which one has the largest sum. A subarray is defined by its start and end index, so we try every valid pair.

For each starting index i, we extend the subarray one element at a time, adding each new element to a running sum. This way we don't recalculate the sum from scratch for every subarray, which saves a loop compared to the truly naive O(n^3) approach.

Algorithm

  1. Initialize maxSum to the first element (since the subarray must contain at least one element)
  2. For each starting index i from 0 to n-1:
    • Initialize currentSum to 0
    • For each ending index j from i to n-1:
      • Add nums[j] to currentSum
      • Update maxSum if currentSum is larger
  3. Return maxSum

Example Walkthrough

1i=0, j=0: sum=-2, maxSum=-2
0
i
-2
j
1
1
2
-3
3
4
4
-1
5
2
6
1
7
-5
8
4
1/12

Code

For every starting index, we scan forward through the rest of the array. What if, instead of checking every pair, we could process each element exactly once and decide on the spot whether to extend the current subarray or start fresh?

Approach 2: Kadane's Algorithm

Intuition

Here's the key insight: at each position in the array, the maximum subarray ending at that position is either the element itself, or the element plus the maximum subarray ending at the previous position.

You're standing at index i, and you know the best subarray sum that ends at index i-1. You have two choices:

  • Extend: Add nums[i] to the previous subarray. This gives you previousBestSum + nums[i].
  • Start fresh: Begin a new subarray at nums[i]. This gives you just nums[i].

When should you start fresh? When previousBestSum is negative. A negative running sum would only drag down whatever comes next. So the decision rule is simple: currentSum = max(nums[i], currentSum + nums[i]).

While making this local decision at every index, we also track the global maximum across all positions. That global maximum is our answer.

Algorithm

  1. Initialize currentSum and maxSum both to nums[0]
  2. For each element from index 1 to n-1:
    • Set currentSum to the larger of nums[i] and currentSum + nums[i]
    • Update maxSum if currentSum is larger
  3. Return maxSum

Example Walkthrough

1Init: currentSum=-2, maxSum=-2
0
-2
1
1
2
-3
3
4
4
-1
5
2
6
1
7
-5
8
4
1/10

Code

Kadane's is already O(n), which is optimal for this problem since we must look at every element at least once. But the problem asks for a divide and conquer approach as a follow-up. It won't beat Kadane's in time complexity (it's O(n log n)), but it demonstrates a different way of thinking about the problem.

Approach 3: Divide and Conquer

Intuition

The divide and conquer approach splits the array at the midpoint and makes a recursive observation: the maximum subarray is in one of three places:

  1. Entirely in the left half
  2. Entirely in the right half
  3. Crossing the midpoint (starts in the left half, ends in the right half)

We recursively solve the left and right halves. The crossing case is the interesting part: we find the best suffix of the left half (extending from mid leftward) and the best prefix of the right half (extending from mid+1 rightward), then combine them.

Algorithm

  1. Base case: If the subarray has one element, return that element
  2. Find the midpoint mid
  3. Recursively find the maximum subarray sum in the left half: leftMax
  4. Recursively find the maximum subarray sum in the right half: rightMax
  5. Find the maximum crossing subarray sum:
    • Starting from mid, extend left, tracking the best sum: leftCrossMax
    • Starting from mid + 1, extend right, tracking the best sum: rightCrossMax
    • Crossing sum = leftCrossMax + rightCrossMax
  6. Return the maximum of leftMax, rightMax, and the crossing sum

Example Walkthrough

1Split at mid=4: Left=[-2,1,-3,4], Right=[-1,2,1,-5,4]
0
-2
1
1
2
-3
3
4
4
-1
mid
5
2
6
1
7
-5
8
4
1/8

Code