Problem
Given an integer array, return the sum of the contiguous subarray (containing at least one element) that has the largest sum.
Example:
- Input:
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - Output:
6 - Explanation: The subarray
[4, -1, 2, 1]sums to 6.
A counter-example: nums = [-3, -1, -2] โ output -1 (not 0 โ you must select at least one element, so the least-negative element is the best answer for an all-negative array).
Intuition
At each position you're making a binary choice: extend the running subarray or abandon it and start fresh. The key insight is that a negative running sum is always a liability โ it can only reduce the total of anything appended after it. So whenever the accumulated sum goes negative, it's strictly better to restart from the current element.
Approach 1 โ Brute Force
Try every possible contiguous subarray by iterating over all start and end index pairs, tracking the maximum sum seen.
Steps:
- Initialize
max_sumtonums[0]to correctly handle all-negative arrays. - For each start index
left, resetcurrent_sumto 0. - Extend the window right, adding each element to
current_sum. - Update
max_sumwhenevercurrent_sumexceeds it. - Return
max_sum.
1def maxSubArray(nums: list[int]) -> int:
2 max_sum = nums[0]
3
4 for left in range(len(nums)):
5 current_sum = 0
6 for right in range(left, len(nums)):
7 current_sum += nums[right]
8 max_sum = max(max_sum, current_sum)
9
10 return max_sum- Time: O(nยฒ) โ two nested loops, each up to n iterations.
- Space: O(1) โ only scalar variables, no extra storage.
Approach 2 โ Kadane's Algorithm
A single linear pass. At each element, pick the larger of starting fresh at this element versus extending the previous running sum. Track the global best seen so far.
Steps:
- Initialize both
current_sumandmax_sumtonums[0]โ handles all-negative inputs correctly. - Iterate from index 1 onward.
- At each element, set
current_sum = max(num, current_sum + num)โ restart when the previous running sum would reduce the total. - Update
max_sumifcurrent_sumexceeds it. - Return
max_sum.
1def maxSubArray(nums: list[int]) -> int:
2 current_sum = nums[0]
3 max_sum = nums[0]
4
5 for num in nums[1:]:
6 # restart if the accumulated sum would drag down this element
7 current_sum = max(num, current_sum + num)
8 max_sum = max(max_sum, current_sum)
9
10 return max_sum- Time: O(n) โ single pass through the array.
- Space: O(1) โ two scalar variables regardless of input size.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Brute Force | O(nยฒ) | O(1) | Establishing a baseline in an interview before optimizing |
| Kadane's Algorithm | O(n) | O(1) | Always โ the standard solution for any contiguous subarray sum problem |
Common Mistakes
- Initializing
max_sum = 0: Returns 0 for all-negative arrays like[-3, -1, -2], where the correct answer is-1. Always initialize tonums[0]. - Resetting
current_sumto 0 instead of the current element:current_sum = 0discards the current element entirely on a reset, producing wrong answers when every element is negative. The correct reset is captured bymax(num, current_sum + num). - Starting the loop at index 0 after initializing from
nums[0]: Processingnums[0]a second time can inflate the result on inputs that start with a positive number. - Confusing this with Maximum Product Subarray: The product variant requires tracking both the running maximum and minimum because multiplying by a negative flips the sign โ the simple restart logic here does not apply directly.
- Assuming the answer must be positive: On all-negative inputs the answer is the largest (least negative) single element, not zero. The initialization to
nums[0]and themax(num, ...)restart handle this automatically.
Related Problems
maximum-product-subarrayโ same linear scan, but products require tracking both running max and running min due to sign flipsbest-time-to-buy-and-sell-stockโ equivalent to finding the maximum subarray of the array of daily price differencessubarray-sum-equals-kโ prefix sums to find a subarray matching a specific target instead of the maximumhouse-robberโ linear DP with the same "take this element or skip it" decision at each positionjump-gameโ another greedy linear scan that tracks the best reachable state at each index