The problem
Given an integer array nums, find the subarray with the largest sum, and return its sum.
A subarray is a contiguous non-empty sequence of elements within an array.
Examples
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: The subarray [4,-1,2,1] has the largest sum 6.
Input: nums = [1]
Output: 1
Explanation: The subarray [1] has the largest sum 1.
Input: nums = [5,4,-1,7,8]
Output: 23
Explanation: The subarray [5,4,-1,7,8] has the largest sum 23.
Constraints
- 1 <= nums.length <= 10⁵
- -10⁴ <= nums[i] <= 10⁴
Follow up: If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
Explanation
We can solve this problem in a brute force way by computing every single subarray for every single value. That algorithm will take O(n³) time complexity.
For example, with input nums = [-2,1,-3,4,-1,2,1,-5,4], visual representation will look like this:
Brute Force (Optimized) Solution
func maxSubArray(_ nums: [Int]) -> Int {
let n = nums.count
var res = nums[0]
for i in 0 ..< n {
var curr = 0
for j in i ..< n {
curr += nums[j]
res = max(res, curr)
}
}
return res
}
Explanation
We can slightly optimize the brute force solution with O(n³) time.
Let’s look at how we can do it:
- We are going to start from index
0and iterate over the entire array, - Inside this loop we will have another loop and a property that will keep track of the current sum
curr, - And we will update it after each iteration of the loop.
This solution will take O(n²) time complexity, but we can do better.
Now the question that we need to ask ourselves is: do we need to start at every single value and compute every single subarray, or can we avoid repetitive work?
Time/ Space complexity
- Time complexity: O(n²)
- Space complexity: O(1)
Kadane’s Algorithm Solution
func maxSubArray(_ nums: [Int]) -> Int {
var maxSum = nums[0]
var currSum = 0
for n in nums {
if currSum < 0 {
currSum = 0
}
currSum += n
maxSum = max(maxSum, currSum)
}
return maxSum
}
Explanation
In the previous solution, we learned that we can optimize the brute force solution with O(n²) to linear time of O(n) by eliminating repetitive work.
Let’s look at the example with input nums = [-2,1,-3,4,-1,2,1,-5,4]
-
We start at a value with the negative number
-2and if we sum it with the next value of1, we will receive a negative value of-1. So we can conclude that we can basically ignore the negative prefix value because it is not going to help us find the result, so we are not going to consider it. -
Next, we move to the value of
1and try to find the max subarray with the value of-3, but we can see that when we sum them we receive a negative-2value, so this means that we can skip those values and move to the next. -
Now, we move to the value of
4and sum it with the negative value of-1, that will result in3. After that, we continue without skipping because our sum resulted in a positive value. -
Next, we use our current sum and add the positive value of
2to it, so the result will be5. -
Next, we add
1to our current sum of5, that results in6. -
Next, we add negative
-5to our sum, that results in positive1. -
Lastly, we add
4to our sum, and now our result equals5.
This algorithm takes linear time, where we go through the array once, removing the negative prefix as we compute the total sum.
Time/ Space complexity
- Time complexity: O(n)
- Space complexity: O(1)