You are given a one dimensional array that may contain both positive and negative integers, find the sum of contiguous subarray of numbers which has the largest sum.
For example, if the given array is {-2, -5, 6, -2, -3, 1, 5, -6}, then the maximum subarray sum is 7 (see highlighted elements).
The naive method is to run two loops. The outer loop picks the beginning element, the inner loop finds the maximum possible sum with first element picked by outer loop and compares this maximum with the overall maximum. Finally, return the overall maximum. The time complexity of the Naive method is O(n^2).
Using Divide and Conquer approach, we can find the maximum subarray sum in O(nLogn) time. Following is the Divide and Conquer algorithm.
- Divide the given array in two halves
- Return the maximum of following three
- Maximum subarray sum in left half (Make a recursive call)
- Maximum subarray sum in right half (Make a recursive call)
- Maximum subarray sum such that the subarray crosses the midpoint
The lines 2.a and 2.b are simple recursive calls. How to find maximum subarray sum such that the subarray crosses the midpoint? We can easily find the crossing sum in linear time. The idea is simple, find the maximum sum starting from mid point and ending at some point on left of mid, then find the maximum sum starting from mid + 1 and ending with some point on right of mid + 1. Finally, combine the two and return the maximum among left, right and combination of both.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int max( int a, int b) {
return (a > b) ? a : b;
}
int max( int a, int b, int c) {
return max(max(a, b), c);
}
int maxCrossingSum( int arr[], int l, int m, int h) {
int sum = 0;
int left_sum = INT_MIN;
for ( int i = m; i >= l; i--) {
sum = sum + arr[i];
if (sum > left_sum)
left_sum = sum;
}
sum = 0;
int right_sum = INT_MIN;
for ( int i = m; i <= h; i++) {
sum = sum + arr[i];
if (sum > right_sum)
right_sum = sum;
}
return max(left_sum + right_sum - arr[m], left_sum, right_sum);
}
int maxSubArraySum( int arr[], int l, int h) {
if (l > h)
return INT_MIN;
if (l == h)
return arr[l];
int m = (l + h) / 2;
return max(maxSubArraySum(arr, l, m - 1),
maxSubArraySum(arr, m + 1, h),
maxCrossingSum(arr, l, m, h));
}
int main() {
int arr[] = { 2, 3, 4, 5, 7 };
int n = sizeof (arr) / sizeof (arr[0]);
int max_sum = maxSubArraySum(arr, 0, n - 1);
cout << "Maximum contiguous sum is " << max_sum;
return 0;
}
|
Java
import java.util.*;
class GFG {
static int maxCrossingSum( int arr[], int l, int m,
int h)
{
int sum = 0 ;
int left_sum = Integer.MIN_VALUE;
for ( int i = m; i >= l; i--) {
sum = sum + arr[i];
if (sum > left_sum)
left_sum = sum;
}
sum = 0 ;
int right_sum = Integer.MIN_VALUE;
for ( int i = m; i <= h; i++) {
sum = sum + arr[i];
if (sum > right_sum)
right_sum = sum;
}
return Math.max(left_sum + right_sum - arr[m],
Math.max(left_sum, right_sum));
}
static int maxSubArraySum( int arr[], int l, int h)
{
if (l > h)
return Integer.MIN_VALUE;
if (l == h)
return arr[l];
int m = (l + h) / 2 ;
return Math.max(
Math.max(maxSubArraySum(arr, l, m- 1 ),
maxSubArraySum(arr, m + 1 , h)),
maxCrossingSum(arr, l, m, h));
}
public static void main(String[] args)
{
int arr[] = { 2 , 3 , 4 , 5 , 7 };
int n = arr.length;
int max_sum = maxSubArraySum(arr, 0 , n - 1 );
System.out.println( "Maximum contiguous sum is "
+ max_sum);
}
}
|
Python
def maxCrossingSum(arr, l, m, h):
sm = 0
left_sum = - 10000
for i in range (m, l - 1 , - 1 ):
sm = sm + arr[i]
if (sm > left_sum):
left_sum = sm
sm = 0
right_sum = - 1000
for i in range (m, h + 1 ):
sm = sm + arr[i]
if (sm > right_sum):
right_sum = sm
return max (left_sum + right_sum - arr[m], left_sum, right_sum)
def maxSubArraySum(arr, l, h):
if (l > h):
return - 10000
if (l = = h):
return arr[l]
m = (l + h) / / 2
return max (maxSubArraySum(arr, l, m - 1 ),
maxSubArraySum(arr, m + 1 , h),
maxCrossingSum(arr, l, m, h))
arr = [ 2 , 3 , 4 , 5 , 7 ]
n = len (arr)
max_sum = maxSubArraySum(arr, 0 , n - 1 )
print ( "Maximum contiguous sum is " , max_sum)
|
C#
using System;
class GFG {
static int maxCrossingSum( int [] arr, int l, int m,
int h)
{
int sum = 0;
int left_sum = int .MinValue;
for ( int i = m; i >= l; i--) {
sum = sum + arr[i];
if (sum > left_sum)
left_sum = sum;
}
sum = 0;
int right_sum = int .MinValue;
;
for ( int i = m; i <= h; i++) {
sum = sum + arr[i];
if (sum > right_sum)
right_sum = sum;
}
return Math.Max(left_sum + right_sum -arr[m],
Math.Max(left_sum, right_sum));
}
static int maxSubArraySum( int [] arr, int l, int h)
{
if (l > h)
return int .MinValue;
if (l == h)
return arr[l];
int m = (l + h) / 2;
return Math.Max(
Math.Max(maxSubArraySum(arr, l, m-1),
maxSubArraySum(arr, m + 1, h)),
maxCrossingSum(arr, l, m, h));
}
public static void Main()
{
int [] arr = { 2, 3, 4, 5, 7 };
int n = arr.Length;
int max_sum = maxSubArraySum(arr, 0, n - 1);
Console.Write( "Maximum contiguous sum is "
+ max_sum);
}
}
|
PHP
<?php
function maxCrossingSum(& $arr , $l , $m , $h )
{
$sum = 0;
$left_sum = PHP_INT_MIN;
for ( $i = $m ; $i >= $l ; $i --)
{
$sum = $sum + $arr [ $i ];
if ( $sum > $left_sum )
$left_sum = $sum ;
}
$sum = 0;
$right_sum = PHP_INT_MIN;
for ( $i = $m ; $i <= $h ; $i ++)
{
$sum = $sum + $arr [ $i ];
if ( $sum > $right_sum )
$right_sum = $sum ;
}
return max( $left_sum + $right_sum - $arr [ $m ], $left_sum , $right_sum );
}
function maxSubArraySum(& $arr , $l , $h )
{
if ( $l > $h )
return PHP_INT_MIN;
if ( $l == $h )
return $arr [ $l ];
$m = intval (( $l + $h ) / 2);
return max(maxSubArraySum( $arr , $l , $m -1),
maxSubArraySum( $arr , $m + 1, $h ),
maxCrossingSum( $arr , $l , $m , $h ));
}
$arr = array (2, 3, 4, 5, 7);
$n = count ( $arr );
$max_sum = maxSubArraySum( $arr , 0, $n - 1);
echo "Maximum contiguous sum is " . $max_sum ;
?>
|
Javascript
<script>
function max(a,b) { return (a > b) ? a : b; }
function max(a,b,c) { return Math.max(Math.max(a, b), c); }
function maxCrossingSum(arr, l, m,h)
{
let sum = 0;
let left_sum = Number.MIN_VALUE;
for (let i = m; i >= l; i--) {
sum = sum + arr[i];
if (sum > left_sum)
left_sum = sum;
}
sum = 0;
let right_sum = Number.MIN_VALUE;
for (let i = m; i <= h; i++) {
sum = sum + arr[i];
if (sum > right_sum)
right_sum = sum;
}
return max(left_sum + right_sum - arr[m], left_sum, right_sum);
}
function maxSubArraySum(arr, l,h)
{
if (l > h)
return Number.MIN_VALUE;
if (l == h)
return arr[l];
let m = parseInt((l + h) / 2, 10);
return max(maxSubArraySum(arr, l, m-1),
maxSubArraySum(arr, m + 1, h),
maxCrossingSum(arr, l, m, h));
}
let arr = [ 2, 3, 4, 5, 7 ];
let n = arr.length;
let max_sum = maxSubArraySum(arr, 0, n - 1);
document.write( "Maximum contiguous sum is " + max_sum);
</script>
|
OutputMaximum contiguous sum is 21
Time Complexity: maxSubArraySum() is a recursive method and time complexity can be expressed as following recurrence relation.
T(n) = 2T(n/2) + Θ(n)
Time Complexity : O(nlogn)
Auxiliary Space: O(1).
The above recurrence is similar to Merge Sort and can be solved either using Recurrence Tree method or Master method. It falls in case II of Master Method and solution of the recurrence is Θ(nLogn).
The Kadane’s Algorithm for this problem takes O(n) time. Therefore the Kadane’s algorithm is better than the Divide and Conquer approach, but this problem can be considered as a good example to show power of Divide and Conquer. The above simple approach where we divide the array in two halves, reduces the time complexity from O(n^2) to O(nLogn).
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.