{x}
blog image

Maximum Subarray

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.

Solution Explanation:

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.

Solution 1: Dynamic Programming

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:

  1. 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.

  2. Iteration: Iterate through the array starting from the second element. For each element x:

    • Update 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).
    • Update ans: ans = max(ans, f). The overall maximum sum is the larger between the current ans and the updated f.
  3. 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.

Solution 2: Divide and Conquer

This solution uses a divide-and-conquer approach to recursively find the maximum subarray sum.

Algorithm:

  1. Base Case: If the subarray has only one element, return that element as the maximum sum.

  2. Recursive Step: Divide the subarray into two halves. Recursively find the maximum subarray sum in the left half (lsum) and the right half (rsum).

  3. 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.

  4. 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.

Code Examples (Python):

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.