You are given an array of integers. Write a function to find the contiguous subarray with the largest sum and return that sum.
For example:
[-2, 1, -3, 4, -1, 2, 1, -5, 4]
, the contiguous subarray [4, -1, 2, 1]
has the largest sum = 6.[1, 2, 3, 4, 5]
, the contiguous subarray [1, 2, 3, 4, 5]
has the largest sum = 15.[-1, -2, -3]
, the contiguous subarray [-1]
has the largest sum = -1.Your function should be efficient and handle arrays with both positive and negative numbers. Explain the time complexity of your solution. Can you implement this using dynamic programming? Are there other approaches? Discuss the tradeoffs of the various potential solutions.
This question asks us to find the contiguous subarray within a given array of integers that has the largest sum. Let's explore different approaches to solve this problem, analyze their time and space complexities, and discuss their tradeoffs.
A simple approach is to consider all possible subarrays and calculate the sum of each subarray. We can then keep track of the maximum sum encountered so far.
def max_subarray_brute_force(nums):
max_sum = float('-inf') # Initialize with negative infinity
n = len(nums)
for i in range(n):
for j in range(i, n):
current_sum = 0
for k in range(i, j + 1):
current_sum += nums[k]
max_sum = max(max_sum, current_sum)
return max_sum
# Example usage
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(f"Maximum subarray sum (brute force): {max_subarray_brute_force(nums)}")
n
times.n - i
times in the worst case, which is still O(n).j - i + 1
times in the worst case, which is also O(n).We can optimize the brute force approach by calculating the subarray sum more efficiently. Instead of recomputing the sum for each subarray, we can reuse the sum from the previous iteration.
def max_subarray_improved_brute_force(nums):
max_sum = float('-inf')
n = len(nums)
for i in range(n):
current_sum = 0
for j in range(i, n):
current_sum += nums[j]
max_sum = max(max_sum, current_sum)
return max_sum
# Example usage
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(f"Maximum subarray sum (improved brute force): {max_subarray_improved_brute_force(nums)}")
n
times.n - i
times in the worst case, which is still O(n).Kadane's algorithm is an efficient dynamic programming approach to solve this problem. It maintains two variables:
max_so_far
: Stores the maximum sum found so far.current_max
: Stores the maximum sum ending at the current position.The algorithm iterates through the array, updating current_max
by choosing the maximum between the current element and the sum of the current element and the previous current_max
. max_so_far
is updated with the maximum value between the current max_so_far
and current_max
.
def max_subarray_kadane(nums):
max_so_far = float('-inf')
current_max = 0
for i in range(len(nums)):
current_max = max(nums[i], current_max + nums[i])
max_so_far = max(max_so_far, current_max)
return max_so_far
# Example usage
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(f"Maximum subarray sum (Kadane's algorithm): {max_subarray_kadane(nums)}")
Another approach is to use divide and conquer. The main idea is to divide the array into two halves, recursively find the maximum subarray sum in each half, and then find the maximum subarray sum that crosses the midpoint.
def max_crossing_subarray(nums, low, mid, high):
left_sum = float('-inf')
current_sum = 0
for i in range(mid, low - 1, -1):
current_sum += nums[i]
left_sum = max(left_sum, current_sum)
right_sum = float('-inf')
current_sum = 0
for i in range(mid + 1, high + 1):
current_sum += nums[i]
right_sum = max(right_sum, current_sum)
return left_sum + right_sum
def max_subarray_divide_and_conquer(nums, low, high):
if low == high:
return nums[low]
mid = (low + high) // 2
return max(
max_subarray_divide_and_conquer(nums, low, mid),
max_subarray_divide_and_conquer(nums, mid + 1, high),
max_crossing_subarray(nums, low, mid, high),
)
def max_subarray_dc(nums):
return max_subarray_divide_and_conquer(nums, 0, len(nums) - 1)
# Example usage
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(f"Maximum subarray sum (divide and conquer): {max_subarray_dc(nums)}")
Approach | Time Complexity | Space Complexity | Advantages | Disadvantages |
---|---|---|---|---|
Brute Force | O(n^3) | O(1) | Simple to understand | Inefficient for large arrays |
Improved Brute Force | O(n^2) | O(1) | Better than brute force | Still not optimal |
Kadane's Algorithm | O(n) | O(1) | Most efficient, simple | None |
Divide and Conquer | O(n log n) | O(log n) | Illustrates divide and conquer | More complex, less efficient than Kadane's |
Kadane's algorithm handles both of these cases correctly.
Kadane's algorithm provides the most efficient solution for finding the maximum contiguous subarray sum, with a time complexity of O(n) and a space complexity of O(1). It's easy to implement and understand, making it the preferred choice for this problem.