|
| 1 | +# Maximum (Sum) Subarray |
| 2 | + |
| 3 | +## Naïve solution |
| 4 | + |
| 5 | +This is quite an interesting problem, and lends itself to a rather straightforward |
| 6 | +naive solution. Basically if we were to try and find the subarray with the largest sum |
| 7 | +(the maximum sum subarray), we could do so pretty easily by just seeing what the maximum |
| 8 | +possible subarray starting at a given element would be, and just do that for each element, |
| 9 | +keeping track of the max. Consider the following array: |
| 10 | + |
| 11 | +[1, 2, -4, 5, -2, 9] |
| 12 | + |
| 13 | +All of the subarrays starting with `1` are: |
| 14 | + |
| 15 | +| Subarray | Sum | |
| 16 | +|---------------|-----| |
| 17 | +| [1] | 1 | |
| 18 | +| [1, 2] | 3 | |
| 19 | +| [1, 2, -4] | -1 | |
| 20 | +| [1, 2, -4, 5] | 4 | |
| 21 | +| [...so on] | x | |
| 22 | + |
| 23 | +The max of which is finally 11. We can keep track of this max, and compare it against the max of |
| 24 | +all of the other `n - 1` tables. We can see that the number of subarrays at a given index is bounded |
| 25 | +by `n`, thus making this trivial solution quite slow. Ultimately in this example, we'll see that the |
| 26 | +max of the max subarrays has a sum of 12, and is the array [5, -2, 9]. |
| 27 | + |
| 28 | +### Complexity analysis: |
| 29 | + |
| 30 | + - Time complexity: O(n<sup>2</sup>) |
| 31 | + - Space complexity: O(1) |
| 32 | + |
| 33 | +## Optimal Solution (dynamic programming) |
| 34 | + |
| 35 | +In the above example, we're doing a ton of work. It'd be nice to make the realization that the reason |
| 36 | +[5, -2, 9] is the maximum subarray, as opposed to [1, 2, -4, 5, -2, 9], is because the subarray |
| 37 | +[1, 2, -4] has a negative sum, so any subarray concatenated onto it is damaged by having it as a prefix. |
| 38 | +In other words, when we get to the point where we are to see what the result of adding `5` to [1, 2, -4] |
| 39 | +will be, we can optimize our approach by saying "Wait, that's less than just starting over at `5`. No need |
| 40 | +to tack `5` onto the negative prefix if I'd be in a better place just starting over at `5`". |
| 41 | + |
| 42 | +It feels like we just skipped over all subarrays that could start with `2` here, or for that matter, |
| 43 | +any value in between the original start, and the new start that we jumped to right? We did! And the reason |
| 44 | +that's ok is because by the time we got to those values, it was still beneficial to have the prefix subarray |
| 45 | +we started before getting there. There's no reason to drop the `1`, from [1, 2, ...], because it'll just lead |
| 46 | +to a lower value. Any subarray starting with `2` can _only be enhanced_ by adding `1` to the beginning. In other |
| 47 | +words, by the time we got to `2`, we didn't have a reason to drop the prefix, because it was helping. Finally, when |
| 48 | +we dipped into the negatives, we realized it'd make more sense to just start over. This solution is nice, and is |
| 49 | +basically a sliding window kinda solution rooted in dynamic programming principles. |
| 50 | + |
| 51 | +This is exactly the logic we use in the approach based off of Kadane's maximum sum subarray algorithm. It |
| 52 | +is a dynamic programming solution, where we essentially keep track of what the maximum sum subarray could be |
| 53 | +if it were to _end_ at any given element. If the sum is ever negative, we know that we can be in a better place |
| 54 | +by starting over at the next not-so-bad solo value. To read more about Kadane's algorithm approach, check out my |
| 55 | +[blog post](https://blog.domfarolino.com/Maximum-Subarray-Study/) on this topic, which goes into much more detail. |
| 56 | + |
| 57 | +### Complexity analysis: |
| 58 | + |
| 59 | + - Time complexity: O(n) |
| 60 | + - Space complexity: O(1) |
| 61 | + |
| 62 | +## Performance analysis |
| 63 | + |
| 64 | +Of course the difference between O(n<sup>2</sup>) and O(n) is probably obvious to most of the |
| 65 | +readers here, but since it's fun creating and analyzing data, here's a nifty chart I made with gnuplot: |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | +For more reading, check out my [blog post](https://blog.domfarolino.com/Maximum-Subarray-Study/) post which |
| 70 | +goes into a little more detail. |
0 commit comments