Maximum Subarray (LC 53)
On this page
Pattern: Dynamic Programming / Kadane’s Algorithm
Difficulty: Medium
Key Concept: Either extend the best subarray ending at the previous index, or start fresh at the current element—whichever gives a larger sum.
Problem Statement
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum, and return that sum.
A subarray is a consecutive portion of the array.
Input
nums— integer array (non-empty)
Output
int— maximum possible sum over all non-empty contiguous subarrays
Example
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]→6(subarray[4, -1, 2, 1]).
1. Algorithm & Pseudocode
Brute force
- Initialize
besttonums[0](or negative infinity if you prefer, but array is non-empty). - For each start index
ifrom0ton - 1: - Set
runSum = 0. - For each end index
jfromiton - 1: - Add
nums[j]torunSum. - If
runSum > best, setbest = runSum. - Return
best.
Optimal (Kadane)
- Initialize
best = nums[0],cur = nums[0]. - For each index
kfrom1ton - 1: - Set
cur = max(nums[k], cur + nums[k])— either restart atnums[k]or extend the previous subarray. - Set
best = max(best, cur). - Return
best.
2. Step-by-Step Analysis (Beginner-Friendly)
Why brute force is correct
Every contiguous subarray is defined by a start i and end j with i ≤ j. The double loop visits all of them and tracks the maximum sum. Nothing is missed.
Why brute force is slow
There are (O(n^2)) subarrays, and the inner loop adds one element each time—still (O(n^2)) total work. For large (n), this is too slow.
Why Kadane works
Focus on subarrays that end at position k. The best one either:
- Starts fresh at
k(onlynums[k]), useful when everything before drags the sum down, or - Extends the best subarray ending at
k - 1, because that continuation addsnums[k]to a already-known optimal “tail.”
Taking the maximum of those two choices is exactly the best subarray ending at k. The global answer is the maximum of those “ending at k” values over all k.
Why we need “restart”
If cur becomes very negative, adding more positive numbers later might still lose to starting over at a large positive value. Example: [ -2, 1 ] — after -2, extending gives -1, but restarting at 1 gives 1.
ASCII — extending vs restarting
nums: [-2, 1, -3, 4, ...]
^
at k=1: cur was -2
max(1, -2+1) = max(1,-1) = 1 → fresh start wins
3. The Dry Run
Input: nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
| Step | k |
nums[k] |
cur (after) |
best (after) |
Choice (conceptually) |
|---|---|---|---|---|---|
| init | 0 | -2 | -2 | -2 | start |
| 1 | 1 | 1 | 1 | 1 | max(1, -2+1)=1 |
| 2 | 2 | -3 | -2 | 1 | max(-3, 1-3)=-2 |
| 3 | 3 | 4 | 4 | 4 | max(4, -2+4)=4 |
| 4 | 4 | -1 | 3 | 4 | max(-1, 4-1)=3 |
| 5 | 5 | 2 | 5 | 5 | max(2, 3+2)=5 |
| 6 | 6 | 1 | 6 | 6 | max(1, 5+1)=6 |
| 7 | 7 | -5 | 1 | 6 | max(-5, 6-5)=1 |
| 8 | 8 | 4 | 5 | 6 | max(4, 1+4)=5 |
Result: 6.
4. Java Solution
Brute Force
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int best = nums[0];
for (int i = 0; i < n; i++) {
int runSum = 0;
for (int j = i; j < n; j++) {
runSum += nums[j];
if (runSum > best) {
best = runSum;
}
}
}
return best;
}
}
Time: (O(n^2)).
Space: (O(1)).
Optimal
class Solution {
public int maxSubArray(int[] nums) {
int best = nums[0];
int cur = nums[0];
for (int k = 1; k < nums.length; k++) {
cur = Math.max(nums[k], cur + nums[k]);
best = Math.max(best, cur);
}
return best;
}
}
Time: (O(n)) — single pass.
Space: (O(1)).
5. The “Java vs. Others” Edge
Math.maxavoids manual branches and reads clearly;Integer.MIN_VALUEis not needed if you initializebestandcurfromnums[0](array non-empty per problem).- Kadane is often written with
curstarting at0and different initialization; the version above matches the “ending at k” story and handles all-negative arrays (e.g.[-3,-2]→-2) becausecurresets viamax(nums[k], ...). - No collections required—pure
intaccumulation is cache-friendly and simple on the JVM.
6. Complexity Summary
| Approach | Time | Space | Notes |
|---|---|---|---|
| Brute Force | (O(n^2)) | (O(1)) | Tries every (i, j) subarray. |
| Optimal (Kadane) | (O(n)) | (O(1)) | One pass; constant extra variables. |