53. Maximum Subarray
DifficultyMedium
Description
Given an integer array nums, find the subarray with the largest sum, and return its sum.
Example 1:
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.
Example 2:
Input: nums = [1] Output: 1 Explanation: The subarray [1] has the largest sum 1.
Example 3:
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 <= 105-104 <= nums[i] <= 104
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.
Solutions
Solution 1: Dynamic Programming
Thinking
The first idea is to enumerate every pair of endpoints and sum, in \(O(n^2)\) or \(O(n^3)\). \(n \le 10^5\) will time out.
The waste is recomputing overlapping subarrays. With the right endpoint fixed at \(i\), the best left end either continues the previous segment (if its sum is positive) or starts over at \(i\).
So let \(f[i]\) be the best sum ending at \(i\). It depends only on \(f[i-1]\), so one rolling variable suffices; the answer is the max along the way.
We define \(f[i]\) to represent the maximum sum of a contiguous subarray ending at element \(\textit{nums}[i]\). Initially, \(f[0] = \textit{nums}[0]\). The final answer we seek is \(\max_{0 \leq i < n} f[i]\).
Consider \(f[i]\) for \(i \geq 1\). Its state transition equation is:
That is:
Since \(f[i]\) is only related to \(f[i - 1]\), we can use a single variable \(f\) to maintain the current value of \(f[i]\) and perform the state transition. The answer is \(\max_{0 \leq i < n} f\).
The time complexity is \(O(n)\), where \(n\) is the length of the array \(\textit{nums}\). The space complexity is \(O(1)\).
1 2 3 4 5 6 7 | |
1 2 3 4 5 6 7 8 9 10 | |
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 | |
Solution 2: Divide and Conquer
Thinking
Solution 1 is already \(O(n)\) time and \(O(1)\) space. The follow-up asks for divide and conquer, but DP's recurrence is linear in the right endpoint and does not split into disjoint halves.
What it lacks is another observation: the best subarray lies entirely on the left, entirely on the right, or crosses the midpoint. Crossing means a max suffix on the left plus a max prefix on the right. Time becomes \(O(n \log n)\); we use it for the follow-up, not for speed.
Split the array at the midpoint. The answer is the max of the left half, the right half, and the best subarray that crosses the midpoint (max suffix of the left plus max prefix of the right).
The time complexity is \(O(n \log n)\) and the space complexity is \(O(\log n)\), where \(n\) is the length of the array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |