I assume your questions is to find the contiguous subarray(containing at least one number) which has the largest sum. Otherwise, the problem is pretty trivial as you can just pick all the positive numbers.
There are 3 solutions that are better than the O(N^2) brute force solution. N is the length of the input array.
- Dynamic programming. O(N) runtime, O(N) space
Since the subarray contains at least one number, we know that there are only N possible candidates: subarray that ends at A[0], A[1]...... A[N - 1]
For the subarray that ends at A[i], we have the following optimal substructure:
maxSum[i] = max of {maxSum[i - 1] + A[i], A[i]};
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
- Prefix sum, O(N) runtime, O(1) space
Maintain a minimum sum variable as you iterate through the entire array. When visiting each number in the input array, update the prefix sum variable currSum. Then update the maximum sum and minimum sum shown in the following code.
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
- Divide and conquer, O(N * logN) runtime
Divide the original problem into two subproblems and apply this principle recursively using the following formula.
Let A[0,.... midIdx] be the left half of A, A[midIdx + 1, ..... A.length - 1] be the right half of A. leftSumMax is the answer of the left subproblem, rightSumMax is the answer of the right subproblem.
The final answer will be one of the following 3:
1. only uses numbers from the left half (solved by the left subproblem)
2. only uses numbers from the right half (solved by the right subproblem)
3. uses numbers from both left and right halves (solved in O(n) time)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}