Problem overview
Given an IntArray named nums that can hold positive and negative integers, maxSumSubarray returns the largest sum of any non-empty continuous run of elements. For [-2, -5, 6, -2, -3, 1, 5, -6] the answer is 7, from the run [6, -2, -3, 1, 5].
Approach
The brute force tries every start and end and adds up each run, which is O(n^2) with a running sum or O(n^3) without one. The lesson wants O(n) time and O(1) extra space.
Kadane's algorithm looks at the question from the right edge. Let maxSum be the best sum of a subarray that ends at the current element. That subarray is either just the current element, or the current element added to the best subarray ending at the previous element. We only extend the previous one if its sum helps, that is, if it is positive:
maxSum = value + max(previous maxSum, 0)
The answer is the biggest maxSum seen at any position, because the best subarray has to end somewhere.
Trace on the example, with maxSum starting at 0:
| value | maxSum | result |
|---|---|---|
| -2 | -2 | -2 |
| -5 | -5 | -2 |
| 6 | 6 | 6 |
| -2 | 4 | 6 |
| -3 | 1 | 6 |
| 1 | 2 | 6 |
| 5 | 7 | 7 |
| -6 | 1 | 7 |
After the -5, the running sum is negative, so at 6 the algorithm starts fresh instead of dragging the negative prefix along.
Step by step
- Create
resultas avarequal tonums[0]. This is the best sum found so far. Don't start it at 0: if every number is negative, the best subarray is a single negative element, and 0 would be a wrong answer because the empty subarray isn't allowed.nums[0]is a real subarray sum, so it is a safe start. - Create
maxSumas avarequal to 0. It is the best sum of a subarray ending at the current position. Starting at 0 stands for "nothing before the first element". - Loop over the elements with
for (value in nums). The namevalueis used becausevalis a keyword. - Update
maxSumwithvalue + maxOf(maxSum, 0). If the previous sum is positive, extend it; if it is zero or negative, drop it and start a new subarray at this element. - Update
resultwithmaxOf(result, maxSum). - Return
resultafter the loop.
The solution in Kotlin
class Solution {
fun maxSumSubarray(nums: IntArray): Int {
var result = nums[0]
var maxSum = 0
for (value in nums) {
maxSum = value + maxOf(maxSum, 0)
result = maxOf(result, maxSum)
}
return result
}
}
Kotlin details worth knowing:
for (value in nums)iterates over the elements directly, with no index. Both variables arevarbecause they change in every iteration.maxOf(a, b)returns the larger of two numbers. It replaces anif/elseand keeps the recurrence on one line.- The function reads
nums[0], so an empty array throws anArrayIndexOutOfBoundsException. The problem implies at least one element. - Sums are
Int, 32 bits, and overflow wraps silently. With inputs whose sum could pass about 2.1 billion, change the types toLong.
Complexity
- Time:
O(n). The array is read once, with constant work per element. - Space:
O(1). OnlyresultandmaxSumare stored.
Edge cases and common mistakes
- All negative numbers. For
[-4, -2, -7]the answer is-2, the largest single element. Startingresultat 0 would return 0. - A single element. The loop runs once,
maxSumequals that element, andresultstays the same. The answer is the element itself. - Mixing up the two variables.
maxSummust end at the current element, so it can drop earlier values.resultkeeps the best over all positions and must never decrease. - Resetting to 0 instead of to the element. Writing
maxSum = maxOf(maxSum + value, 0)allows an empty subarray and breaks the all-negative case. - All zeros. The answer is 0.
Testing
[-2, -5, 6, -2, -3, 1, 5, -6]returns7.[-4, -2, -7]returns-2.[5]returns5.[1, 2, 3]returns6.