Given an integer array nums
, find the
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
The Maximum Subarray problem can be solved using Kadane's Algorithm, which efficiently finds the subarray with the largest sum in time complexity.
Approach: Kadane's Algorithm
-
Idea:
- Use a variable
currentSum
to track the maximum sum of the subarray ending at the current index. - Use another variable
maxSum
to store the global maximum sum across all subarrays.
- Use a variable
-
Steps:
- Traverse the array.
- At each index, decide whether to:
- Continue the current subarray by adding the current element.
- Start a new subarray with the current element.
- Update
maxSum
to keep track of the maximum subarray sum seen so far.
-
Key Formula:
currentSum = Math.Max(nums[i], currentSum + nums[i])
maxSum = Math.Max(maxSum, currentSum)
-
Initialization:
currentSum
starts as the first element (nums[0]
).maxSum
also starts asnums[0]
.
Implementation:
public class Solution {
public int MaxSubArray(int[] nums) {
// Initialize currentSum and maxSum with the first element
int currentSum = nums[0];
int maxSum = nums[0];
// Traverse the array starting from the second element
for (int i = 1; i < nums.Length; i++) {
// Update currentSum: include nums[i] in the subarray or start fresh
currentSum = Math.Max(nums[i], currentSum + nums[i]);
// Update maxSum with the maximum sum found so far
maxSum = Math.Max(maxSum, currentSum);
}
return maxSum;
}
}
Explanation of Code:
-
Initialization:
currentSum
starts with the first element because the subarray must include at least one element.maxSum
starts as the first element because it is the largest sum seen initially.
-
Iterating Through the Array:
- For each
nums[i]
, decide:- Add
nums[i]
to the existing subarray (currentSum + nums[i]
). - Start a new subarray with
nums[i]
.
- Add
- Update
maxSum
to store the largest sum encountered.
- For each
-
Returning the Result:
- The value of
maxSum
at the end of the loop is the largest subarray sum.
- The value of
Complexity Analysis:
-
Time Complexity:
- : The array is traversed once.
-
Space Complexity:
- : Only a few variables are used.
Examples:
Example 1:
- Input:
nums = [-2,1,-3,4,-1,2,1,-5,4]
- Steps:
- Start with
currentSum = -2
,maxSum = -2
. - Update
currentSum
as1
,maxSum
as1
. - Continue until
maxSum
becomes6
(subarray[4, -1, 2, 1]
).
- Start with
- Output:
6
.
Example 2:
- Input:
nums = [1]
- Output:
1
.
Example 3:
- Input:
nums = [5,4,-1,7,8]
- Output:
23
(subarray[5, 4, -1, 7, 8]
).
This solution efficiently handles both small and large inputs, including edge cases like arrays with all negative numbers or a single element.
The Divide and Conquer approach for the Maximum Subarray problem is an alternative to Kadane's algorithm. It splits the array into two halves recursively and combines the results to find the maximum subarray sum.
Approach: Divide and Conquer
-
Divide:
- Split the array into two halves at the middle index.
-
Conquer:
- Recursively find the maximum subarray sum for the left and right halves.
-
Combine:
- Compute the maximum subarray sum that spans across the middle of the array.
-
Final Result:
- The maximum subarray sum for the current array is the maximum of:
- Maximum subarray sum in the left half.
- Maximum subarray sum in the right half.
- Maximum subarray sum spanning the middle.
- The maximum subarray sum for the current array is the maximum of:
Implementation:
public class Solution {
public int MaxSubArray(int[] nums) {
return MaxSubArrayDivideAndConquer(nums, 0, nums.Length - 1);
}
private int MaxSubArrayDivideAndConquer(int[] nums, int left, int right) {
// Base case: single element
if (left == right) {
return nums[left];
}
// Find the middle index
int mid = left + (right - left) / 2;
// Recursively find the maximum subarray sum in the left and right halves
int leftMax = MaxSubArrayDivideAndConquer(nums, left, mid);
int rightMax = MaxSubArrayDivideAndConquer(nums, mid + 1, right);
// Find the maximum subarray sum that crosses the middle
int crossMax = MaxCrossingSubArray(nums, left, mid, right);
// Return the maximum of the three
return Math.Max(Math.Max(leftMax, rightMax), crossMax);
}
private int MaxCrossingSubArray(int[] nums, int left, int mid, int right) {
// Calculate maximum sum in the left half (including the middle element)
int leftSum = int.MinValue, sum = 0;
for (int i = mid; i >= left; i--) {
sum += nums[i];
leftSum = Math.Max(leftSum, sum);
}
// Calculate maximum sum in the right half
int rightSum = int.MinValue;
sum = 0;
for (int i = mid + 1; i <= right; i++) {
sum += nums[i];
rightSum = Math.Max(rightSum, sum);
}
// Combine the results from both halves
return leftSum + rightSum;
}
}
Explanation of Code:
-
Recursive Splitting:
- The array is split into two halves until each segment contains only one element.
-
Base Case:
- If
left == right
, the subarray contains only one element, and the result is the value of that element.
- If
-
Crossing Subarray:
- To compute the maximum sum across the middle, iterate:
- From the middle to the left for the left sum.
- From the middle to the right for the right sum.
- Combine these sums for the cross-sum.
- To compute the maximum sum across the middle, iterate:
-
Result:
- The result for the current segment is the maximum of:
- The left segment sum.
- The right segment sum.
- The cross-segment sum.
- The result for the current segment is the maximum of:
Complexity Analysis:
-
Time Complexity:
- , solving to .
- The recursion divides the array into two halves and processes them.
-
Space Complexity:
- for recursion stack.
Examples:
Example 1:
- Input:
nums = [-2,1,-3,4,-1,2,1,-5,4]
- Divide:
- Left:
[-2,1,-3,4]
, Right:[-1,2,1,-5,4]
- Left:
- Combine:
- Max left:
4
, Max right:4
, Max cross:6
.
- Max left:
- Output:
6
.
Example 2:
- Input:
nums = [1]
- Base case: Return
1
.
Example 3:
- Input:
nums = [5,4,-1,7,8]
- Divide:
- Left:
[5,4,-1]
, Right:[7,8]
.
- Left:
- Combine:
- Max left:
8
, Max right:15
, Max cross:23
.
- Max left:
- Output:
23
.
Comparison with Kadane's Algorithm:
Aspect | Kadane's Algorithm | Divide and Conquer |
---|---|---|
Time Complexity | ||
Space Complexity | ||
Approach | Iterative | Recursive |
Preferred for | Simplicity, performance | Teaching recursion |
Kadane’s algorithm is faster and simpler for competitive programming, while the Divide and Conquer approach is useful for understanding recursive problem-solving techniques.