Last Updated: March 22, 2026
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.
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.-10^4 <= nums[i] <= 10^4), so we can't simply skip negatives or use a sliding window that assumes monotonic growth.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.
maxSum to the first element (since the subarray must contain at least one element)i from 0 to n-1:currentSum to 0j from i to n-1:nums[j] to currentSummaxSum if currentSum is largermaxSummaxSum and currentSum) regardless of input size.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?
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:
nums[i] to the previous subarray. This gives you previousBestSum + nums[i].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.
Kadane's algorithm is really dynamic programming in disguise. If we define dp[i] as the maximum subarray sum ending at index i, then the recurrence is: dp[i] = max(nums[i], dp[i-1] + nums[i]). The answer is the maximum value across all dp[i]. Since dp[i] only depends on dp[i-1], we don't need an array at all. A single variable currentSum is enough. That's why the space complexity is O(1).
The beauty of this approach is that it never looks backward. At each index, it makes the locally optimal choice (extend or restart), and the global maximum captures the best subarray found during the entire scan.
currentSum and maxSum both to nums[0]currentSum to the larger of nums[i] and currentSum + nums[i]maxSum if currentSum is largermaxSumcurrentSum and maxSum) regardless of input size.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.
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:
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.
midleftMaxrightMaxmid, extend left, tracking the best sum: leftCrossMaxmid + 1, extend right, tracking the best sum: rightCrossMaxleftCrossMax + rightCrossMaxleftMax, rightMax, and the crossing sum