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.
The problem asks to find the contiguous subarray within a given integer array that has the maximum sum. Two solutions are provided: dynamic programming and divide and conquer.
This approach uses dynamic programming to efficiently find the maximum subarray sum. It iterates through the array, keeping track of the maximum sum ending at the current position.
Algorithm:
Initialization: Initialize ans
and f
to the first element of the array. ans
will store the overall maximum sum, and f
will store the maximum sum ending at the current position.
Iteration: Iterate through the array starting from the second element. For each element x
:
f
: f = max(f, 0) + x
. This means the maximum sum ending at the current position is either the sum including the previous maximum sum (if positive) or just the current element itself (if the previous sum was negative).ans
: ans = max(ans, f)
. The overall maximum sum is the larger between the current ans
and the updated f
.Return: Return ans
, which holds the maximum subarray sum.
Time Complexity: O(n), where n is the length of the input array. The algorithm iterates through the array once.
Space Complexity: O(1), as it uses only a few constant extra variables.
This solution uses a divide-and-conquer approach to recursively find the maximum subarray sum.
Algorithm:
Base Case: If the subarray has only one element, return that element as the maximum sum.
Recursive Step: Divide the subarray into two halves. Recursively find the maximum subarray sum in the left half (lsum
) and the right half (rsum
).
Cross-Subarray Sum: Find the maximum sum that crosses the midpoint (csum
). This involves iterating from the midpoint towards the left and right, calculating the maximum sums in each direction and adding them.
Return: Return the maximum of lsum
, rsum
, and csum
.
Time Complexity: O(n log n), where n is the length of the input array. The recursive calls divide the problem into smaller subproblems, resulting in logarithmic time complexity. The linear time spent in crossMaxSub
function at each level combines with the logarithmic number of levels, resulting in an overall O(n log n) time complexity.
Space Complexity: O(log n), due to the recursive calls. The recursion depth is proportional to the logarithm of the input size.
Solution 1 (Dynamic Programming):
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
ans = f = nums[0]
for x in nums[1:]:
f = max(f, 0) + x
ans = max(ans, f)
return ans
Solution 2 (Divide and Conquer):
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
def crossMaxSub(nums, left, mid, right):
lsum = rsum = 0
lmx = rmx = float('-inf') #Use float('-inf') instead of -inf for better compatibility.
for i in range(mid, left - 1, -1):
lsum += nums[i]
lmx = max(lmx, lsum)
for i in range(mid + 1, right + 1):
rsum += nums[i]
rmx = max(rmx, rsum)
return lmx + rmx
def maxSub(nums, left, right):
if left == right:
return nums[left]
mid = (left + right) >> 1
lsum = maxSub(nums, left, mid)
rsum = maxSub(nums, mid + 1, right)
csum = crossMaxSub(nums, left, mid, right)
return max(lsum, rsum, csum)
left, right = 0, len(nums) - 1
return maxSub(nums, left, right)
The other languages mentioned (Java, C++, Go, TypeScript, Rust, JavaScript, C#) follow similar logic, with the primary difference being the syntax and standard library functions used. The core algorithms remain the same.