Largest Sum Contiguous Subarray
Write an efficient C program to find the sum of contiguous subarray within a one-dimensional array of numbers which has the largest sum.
Kadane’s Algorithm:
Initialize:
max_so_far = 0
max_ending_here = 0
Loop for each element of the array
(a) max_ending_here = max_ending_here + a[i]
(b) if(max_ending_here < 0)
max_ending_here = 0
(c) if(max_so_far < max_ending_here)
max_so_far = max_ending_here
return max_so_far
Explanation:
Simple idea of the Kadane's algorithm is to look for all positive contiguous segments of the array (max_ending_here is used for this). And keep track of maximum sum contiguous segment among all positive segments (max_so_far is used for this). Each time we get a positive sum compare it with max_so_far and update max_so_far if it is greater than max_so_far
Lets take the example:
{-2, -3, 4, -1, -2, 1, 5, -3}
max_so_far = max_ending_here = 0
for i=0, a[0] = -2
max_ending_here = max_ending_here + (-2)
Set max_ending_here = 0 because max_ending_here < 0
for i=1, a[1] = -3
max_ending_here = max_ending_here + (-3)
Set max_ending_here = 0 because max_ending_here < 0
for i=2, a[2] = 4
max_ending_here = max_ending_here + (4)
max_ending_here = 4
max_so_far is updated to 4 because max_ending_here greater than max_so_far which was 0 till now
for i=3, a[3] = -1
max_ending_here = max_ending_here + (-1)
max_ending_here = 3
for i=4, a[4] = -2
max_ending_here = max_ending_here + (-2)
max_ending_here = 1
for i=5, a[5] = 1
max_ending_here = max_ending_here + (1)
max_ending_here = 2
for i=6, a[6] = 5
max_ending_here = max_ending_here + (5)
max_ending_here = 7
max_so_far is updated to 7 because max_ending_here is greater than max_so_far
for i=7, a[7] = -3
max_ending_here = max_ending_here + (-3)
max_ending_here = 4
Program:
#include<stdio.h>
int maxSubArraySum(int a[], int size)
{
int max_so_far = 0, max_ending_here = 0;
int i;
for(i = 0; i < size; i++)
{
max_ending_here = max_ending_here + a[i];
if(max_ending_here < 0)
max_ending_here = 0;
if(max_so_far < max_ending_here)
max_so_far = max_ending_here;
}
return max_so_far;
}
/*Driver program to test maxSubArraySum*/
int main()
{
int a[] = {-2, -3, 4, -1, -2, 1, 5, -3};
int n = sizeof(a)/sizeof(a[0]);
int max_sum = maxSubArraySum(a, n);
printf("Maximum contiguous sum is %d\n", max_sum);
getchar();
return 0;
}
Notes:
Algorithm doesn't work for all negative numbers. It simply returns 0 if all numbers are negative. For handling this we can add an extra phase before actual implementation. The phase will look if all numbers are negative, if they are it will return maximum of them (or smallest in terms of absolute value). There may be other ways to handle it though.
Above program can be optimized further, if we compare max_so_far with max_ending_here only if max_ending_here is greater than 0.
int maxSubArraySum(int a[], int size)
{
int max_so_far = 0, max_ending_here = 0;
int i;
for(i = 0; i < size; i++)
{
max_ending_here = max_ending_here + a[i];
if(max_ending_here < 0)
max_ending_here = 0;
/* Do not compare for all elements. Compare only
when max_ending_here > 0 */
else if (max_so_far < max_ending_here)
max_so_far = max_ending_here;
}
return max_so_far;
}
Time Complexity: O(n)
Algorithmic Paradigm: Dynamic Programming
Now try below question
Given an array of integers (possibly some of the elements negative), write a C program to find out the *maximum product* possible by adding 'n' consecutive integers in the array, n <= ARRAY_SIZE. Also give where in the array this sequence of n integers starts.
References:
http://en.wikipedia.org/wiki/Kadane%27s_Algorithm
If an array consists of all negative number then what should be the answer 0 or the smallest negative in array.
//another possible solution may be this(working for -ve numbers) void max_subarray() { int arr[]={-1,2,-3,4,-5,6,-7,9,-8}; int size=9; //kedan's solution modified.. int max_here=arr[0],max_far=0; for(int i=0;i<size;i++) { if(max_here < 0 && arr[i] >=max_here) max_here=arr[i]; else if( max_here > 0) max_here+=arr[i]; if(max_here > max_far) max_far=max_here; } if(max_far==0) cout<<"max:"<<max_here; else cout<<"max:"<<max_far; }If we use memoization than we do not need to consider extra case of all numbers being egative.
#include <algorithm>
#include <iostream>
#include <limits>
using namespace std;
int maxSubsequenceSum(int arr[], int n)
{
if(n==1)
return arr[0];
int sum[n];
sum[0] = arr[0];
int maxSum = numeric_limits<int>::min();
for (int i = 1; i < n; ++i)
{
sum[i] = max(sum[i-1]+arr[i], arr[i]);
if(sum[i] > maxSum)
maxSum = sum[i];
}
return maxSum;
}
int main()
{
int arr[] = {-2,-3,-4,-1,-2,-1,-5,-3};
int n = sizeof(arr)/sizeof(arr[0]);
cout << maxSubsequenceSum(arr, n) << endl;
return 0;
}
/* #include<stdio.h> #include<stdlib.h> int main() { int *a, n, maxsum, sum=0, i, b, c, d; printf("enter no of elements:"); scanf("%d",&n); a=(int *)malloc(sizeof(int)*n); printf("enter elements\n"); for(i=0;i<n;i++) scanf("%d",(a+i)); maxsum=a[0]; d=0; for(i=0;i<n;i++) { sum += a[i]; if(sum > maxsum) { b=d; maxsum = sum; c=i; } if(sum < 0) { sum=0; d=i+1; } } printf("maximum sum is %d\n",maxsum); if(maxsum == 0) printf("all elements are 0\n"); else if(maxsum < 0) { sum=0; for(i=1;i<n;i++) if(a[sum] < a[i]) sum=i; printf("max sum is from %d to %d\n", sum, sum); } else printf("maximum sum is from %d to %d\n",b+1, c+1); return 0; } */For taking care of cases where number are not positive... do this..
If a represents current max. sum, and b represents max. sum so far
then at each element arr[i] do following :
while (i
{a=max(a+arr[i],arr[i]);
b=max(a,b);
i++;}
initially a=b=arr[0];
at end b will give you max. contiguous sum.
/* public int kadaneAlgorithm(int[] input) { int maxSum=input[0]; int sum=0; for(int i=0;i<input.length;i++) { sum=sum+input[i]; if(sum>maxSum) maxSum=sum; if(sum<0) sum=0; } return maxSum; } */A much better and shorter approach:
Also the same can easily be modified to keep track of the sub-array indices.
public static kadane(int[] array) { int max = array[0], currMax = array[0]; for (int i = 1; i < array.length; i++) { currMax = Math.max(array[i], currMax + array[i]); max = Math.max(max, currMax); } return max; }The above one can be used for any type of input.
+ve, -ve and a mix.
Also to handle the edge cases the following can be the start of the method :
public int kadane (int[] array) {
if (array == null || array.length == 0) return Integer.MIN_VALUE;
if (array.length == 1) return array[0];
..
}
Very nice and short one. thanks...
@geeksforgeeks: solution by mohitk looks elegant, simple, covers all cases (as far as I can see) and seems to be providing optimal sol. for all cases. My request to you is to mention the above solution in your main article (as an alternate sol. or otherwise),if possible, so that other will also believe on the correctness of this sol. If you think otherwise about the correctness of this sol. then please let me your comments.
@Mohitk: Thanks buddy for sharing this sol.
@Pavi,
thanks.
Yups, submitted a request for the same to the moderators.
Lets see whether they also feel that my solution is correct.
Nope, ds s actually wrong. For the present case, your code will give the answer 9 which is very clear. For reference, just see: http://ideone.com/mredxe
Hope it helps!
@code123
For the link u pasted and the instance for which its solved, I see 9 as the only max solution for input {-2,-3,4,-1,-2,5,3}.
How is it wrong? and what max do u expect it to give ?
I think you got it wrong. The input considered here at geeksforgeeks is this: {-2, -3, 4, -1, -2, 1, 5, -3}
and its diff from the one at ideone.
Hope it helps now
Nope, ds s actually wrong. For the present case, your code will give the answer 9 which is very clear. For reference, just see: http://ideone.com/mredxe
Hope it helps!:)
A little bit modification on Kadane's algo will work
class Solution { //DP,but with less memory public: int maxSubArray(int A[], int n) { // Start typing your C/C++ solution below // DO NOT write int main() function int maxendinghere=0,maxsofar=-9999; for(int i=0;i<n;i++){ if(maxendinghere<=0)maxendinghere=A[i]; else maxendinghere+=A[i]; if(maxendinghere>maxsofar)maxsofar=maxendinghere; } return maxsofar; } };#include<stdio.h> int main () { int a[] = {-2, -13, 4, -1, -2, 1, 5, -3}; // All working including start and end index // int a[] = {-1, 0, -12}; // All working // int a[] = {-2, -13, 4, -3, -2, 1, 5, -3}; - // For this particular case, all working except wrong start index int size = sizeof(a) / sizeof(a[0]); int sum = a[0], maxsum = a[0]; int start = 0, end = 0; for(int i=1; i<size ;i++) { if(sum + a[i] <= 0){ // -ve +ve, sum = a[i] // +ve -ve, sum = a[i] // -ve -ve, sum = a[i] sum = a[i]; start = i; } else { // -ve +ve, sum = a[i] // +ve -ve, add // +ve +ve, add if(sum < 0) { sum = a[i]; start = i; } else { sum = sum + a[i]; } } if(maxsum < sum) { maxsum = sum; end = i; } // Resetting start and end index for -ve numbers if(start > end) { start = end; } } printf("Max sum = %d, start index = %d, end index = %d\n", maxsum, start, end); return 0; }// A perfect code, it also take into count if all numbers are negative
#include
#include
#include
using namespace std;
int main()
{
int n;
printf("Enter size of array : ");
scanf("%d",&n);
int a[n],i;
printf("Enter elements of array : ");
for(i=0;i<n;i++)
scanf("%d",a+i);
int start,end,sum,maxsum,ind;
sum=start=ind=0;
maxsum=INT_MIN;
for(i=0;isum)
{
sum=a[i];
ind=i;
}
if(sum>maxsum)
{
start=ind;
maxsum=sum;
end=i;
}
}
printf("sum=%d, start=%d, end=%d\n",maxsum,start+1,end+1);
return 0;
}
int max_add(int ary[])
{
int i,cur_max=0,max_value=0,c=0,min=INT_MIN;
for(i=0;i<5;i++)
{
cur_max+=ary[i];
if(ary[i]<0)
{
c++;
if(min<ary[i])
min=ary[i];
}
if(cur_max<0)
cur_max=0;
else
if(max_value<cur_max)
max_value=cur_max;
if(c==5)
max_value=min;
}
return max_value;
}
@All shouldn't be when all no are -ive , maximum of them will be largest subarray thats nothing but only of length or i am missing something ??
Solution for max product. The idea is to precompute the number of negative numbers after a given index. If there is 0 is between, we restart the count.
int maxProduct(int[] a) { int global_max = 0; int local_max = 0; int[] x = numNegatives(a); for (int i = 0; i < a.length; ++i) { if (a[i] > 0 || (a[i] < 0 && x[i] >= 1) || (local_max < 0 && a[i] < 0)) { local_max = (local_max == 0) ? a[i] : local_max * a[i]; } else { local_max = 0; } if (global_max < local_max) { global_max = local_max; } } return global_max; } int[] numNegatives(int[] a) { int[] x = new int[a.length]; int count = 0; for (int n = (a.length - 1); n >= 0; --n) { x[n] = count; if (a[n] == 0) { count = 0; } if (a[n] < 0) { count++; } } return x; }I think it does not work if one of the elements in array is 0
sorry yaar,it works
This doesn't work for input 2, -1, 3, 4,-5,-6,0,1,3,-2,-1.
It gives 120 as output. But the solution is 360
infact it is giving the correct answer because we have to find "maxProduct subArray" not the maximum product of the array..
I don't think the code works for following example,
{-2, 1, 1, -5, -15, 5}
The solution should be -5*-15 = 75, but the output is 10
class MaxSubarray {
public static void main(String[] args) {
int[] intArr = {-2, -3, 4, -1, -2, 1, 5, -3};
//int[] intArr = {3,1,2,-4,5,9,-11,6,7};
//int[] intArr = {-1,-2,-3,-4,-5,-99};
//int[] intArr = {-1,0,0,0,0,0};
int maxSubArraySum = printMaxSumArr(intArr,intArr.length);
System.out.println("maxSubArraySum->"+maxSubArraySum);
}
public static int printMaxSumArr(int[] a, int n) {
int maxSum=0;
int minNeg=0;
boolean allNegative=true;
int[] saveSum = new int[n];
saveSum[0]=a[0];
if(a[0]>0){
allNegative =false;
}
else {
minNeg=a[0];
}
for(int i = 1; i =0){
allNegative=false;
}
else {
minNeg=(minNeg>a[i]?minNeg:a[i]);
}
saveSum[i]=max(saveSum[i-1]+a[i],a[i]);
if(saveSum[i]>maxSum) {
maxSum=saveSum[i];
}
}
if(allNegative){
return minNeg;
}
return maxSum;
}
private static int max(int i, int j) {
return (i>j?i:j);
}
}
class MaxSubarray { public static void main(String[] args) { int[] intArr = {-2, -3, 4, -1, -2, 1, 5, -3}; //int[] intArr = {3,1,2,-4,5,9,-11,6,7}; //int[] intArr = {-1,-2,-3,-4,-5,-99}; //int[] intArr = {-1,0,0,0,0,0}; int maxSubArraySum = printMaxSumArr(intArr,intArr.length); System.out.println("maxSubArraySum->"+maxSubArraySum); } public static int printMaxSumArr(int[] a, int n) { int maxSum=0; int minNeg=0; boolean allNegative=true; int[] saveSum = new int[n]; saveSum[0]=a[0]; if(a[0]>0){ allNegative =false; } else { minNeg=a[0]; } for(int i = 1; i < a.length; i++) { if(a[i]>=0){ allNegative=false; } else { minNeg=(minNeg>a[i]?minNeg:a[i]); } saveSum[i]=max(saveSum[i-1]+a[i],a[i]); if(saveSum[i]>maxSum) { maxSum=saveSum[i]; } } if(allNegative){ return minNeg; } return maxSum; } private static int max(int i, int j) { return (i>j?i:j); } }This is the correct one..
No cases required.
#define forn(i, n) for(int i = 0; i < (int)(n); i++) #define maX(a,b) ((a > b) ? a : b) // minend is max till here (-ve or +ve) // max total max int maxsumcont(vector<int> a) { int max = -INF, minend = 0; forn(i, a.size()) { max = maX(maX(a[i], minend+a[i]), max); minend = maX(minend+a[i], a[i]); } return max; }What if I want to print the elements from which the Largest Sum is formed...
For ex: int a[]={2,4,-4,-1,2,8,-30,3,8};
should print
2,4,-4,-1,2,8
AND
3,8
void findMaxSubArray(int *ar,int n,int &maxSum,int & startIndex, int & startIndex) { int maxSum = INT_MIN; // minimum integer value use #include<climits> int sum = ar[0]; for(int i = 1;i<n;i++) { sum+=ar[i]; if( ar[i] > sum) { startIndex = i; sum = ar[i]; } if(sum>maxSum) { maxSum = sum; endIndex = i; } } }its working for all the cases... as I have checked... if any mistake then plse let me know..
hey nice, this looks the most optimized version
I think 1 correction should be there to update endindex=i when updating startindex=i;
consider last index a[n-1]>sum . then startindex=n-1; while endindex <n-1
or to remove unwanted extra condition that may be needed when printing sol.
/* Paste your code here (You may delete these lines if not writing code) */
void findMaxSubArray(int *ar,int n,int &maxSum,int & startIndex, int & endIndex)
{
int maxSum = INT_MIN; // minimum integer value use #include<climits>
int sum = ar[0];
for(int i = 1;i<n;i++)
{
sum+=ar[i];
if( ar[i] > sum)
{ startIndex = i;
sum = ar[i];
endIndex = i;
}
if(sum>maxSum)
{
maxSum = sum;
endIndex = i; }
}
}
your code will give incorrect answer.
test case : 4 5 -15 1 2
nice and amazing
@geeksforgeeks
If all elements are negative the function will return zero ,
interchanging the if and elseif should work.
Correct me if i am wrong
if (max_so_far < max_ending_here)
max_so_far = max_ending_here;
else if(max_ending_here < 0)
max_ending_here = 0;
It's not if/else-if, rather if/if.
if(condition)
..
if(condition)
..
and I don't think interchanging them will affect the working of program.
/* Paste your code here (You may delete these lines if not writing code) */ //Fully working C code #include <stdio.h> #include <stdlib.h> int main() { int n=0; printf("enter the number of elements in the array\n"); scanf("%d",&n); int a[100],start=0,end=0; printf("\n enter the elements in the array \n"); int i=0; for(i=0;i<n;i++) scanf("%d",&a[i]); int max=0 , current=0; //For handling all negative numbers /* for(j=0;j<n;j++){ if(a[j] <0) sum = max(a[j]); }*/ for(i=0;i<n;i++) { current += a[i]; if(current < 0) { current =0; start =i+1; } if( max < current) { max = current; end = i; } } printf("MAX SUM between indexes a[%d]=%d and a[%d]=%d = %d",start,a[start],end,a[end],max); return 0;; }Code Can Work for Negative Numbers by placing a simple flag.
Check out the Code below.
// MaxSubArray1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; int maxSumArray(int a[], int len) { int max_sum = -32768; int max_here = 0; int flag = 0; for(int i=0;i<len;i++) { max_here += a[i]; if(max_here < 0) { max_here = 0; if(!flag) { if(max_sum < a[i]) max_sum = a[i]; } } else if(max_sum < max_here) { max_sum = max_here; flag = 1; } } return max_sum; } int _tmain(int argc, _TCHAR* argv[]) { int a[] = {-2, -3, -4, -1, -2, -1, -5, -3}; cout<<maxSumArray(a,8); return 0; }void max_sum_sub_array(int *a, int n, int *start, int *end, int *max_sum) { int m_sum = 0x80000000; // min32 int sum = 0; int i_start = 0; int i_end = 0; int s = 0; int i = 0; for(i = 0; i < n; i++) { sum += a[i]; if(sum > m_sum) { m_sum = sum; i_start = s; i_end = i; } if(sum < 0) { sum = 0; s = i + 1; } } *start = i_start; *end = i_end; *max_sum = m_sum; }I guess there is better way to handle all negative numbers.
The following algo will take in account negative as well as positive numbers.
Initialize:
max_so_far = a[0]
max_ending_here = 0
Loop for each element of the array
(a) max_ending_here = max_ending_here + a[i]
(b) if(max_ending_here < a[i])
max_ending_here = a[i]
(c) if(max_so_far < max_ending_here)
max_so_far = max_ending_here
return max_so_far
And so subsequently the code would change automatically.. What say??
yupp,...perfect
Agree.
Is it possible to get the starting and end index of the subarray?
Look at the code in one of my comments below. It returns a MaxSubArrayVO which also includes the sub-array-range along with the sum.
public class MaxSubArray { public static void main(String[] args) { int[] intArr = toIntArray(args); printMaxSumArr(intArr); } public static void printMaxSumArr(int[] in) { int subStart = -1; int subEnd = -1; int subStartCurr = -1; int sumHere = 0; int sumMax = 0; boolean isChangeSubStart = false; for(int i = 0; i < in.length; i++) { if(sumHere == 0) { subStartCurr = -1; } sumHere = sumHere + in[i]; if(sumHere < 0) { sumHere = 0; } if(subStartCurr == -1 && sumHere > 0) { subStartCurr = i; } if(sumHere > sumMax) { sumMax = sumHere; subEnd = i; isChangeSubStart = true; } if(isChangeSubStart) { subStart = subStartCurr; } } System.out.println("MaxSum = " + sumMax); String subArr = ""; for(int i = subStart; i <= subEnd; i++) { subArr = subArr + " " + in[i]; } System.out.println("SubArray =" + subArr); } public static int[] toIntArray(String[] strArr) { int[] intArr = new int[strArr.length]; for(int i = 0; i < strArr.length; i++) { intArr[i] = Integer.parseInt(strArr[i]); } return intArr; } }Edited code with some comments:
public class MaxSubArray { public static void main(String[] args) { /* Modify string array to int array */ int[] intArr = toIntArray(args); /* Print max sum and corresponding sub array */ printMaxSumArr(intArr); } public static void printMaxSumArr(int[] in) { int subStart = -1; int subEnd = -1; int subStartCurr = -1; int sumHere = 0; int sumMax = 0; for(int i = 0; i < in.length; i++) { /* If corresponding to last element was 0, the sub array with a positive sum has not started yet */ if(sumHere == 0) { subStartCurr = -1; } sumHere = sumHere + in[i]; if(sumHere < 0) { sumHere = 0; } /* If sum is positive and the sub array has not yet started, start it */ if(subStartCurr == -1 && sumHere > 0) { subStartCurr = i; } if(sumHere > sumMax) { sumMax = sumHere; /* New max sum found. Time to change start and end index of sub array */ subEnd = i; subStart = subStartCurr; } } System.out.println("MaxSum = " + sumMax); String subArr = ""; for(int i = subStart; i <= subEnd; i++) { subArr = subArr + " " + in[i]; } System.out.println("SubArray =" + subArr); } public static int[] toIntArray(String[] strArr) { int[] intArr = new int[strArr.length]; for(int i = 0; i < strArr.length; i++) { intArr[i] = Integer.parseInt(strArr[i]); } return intArr; } }It should run for both positive and negative inputs.
int maxSubArraySum(int []a, int size) { int max_so_far = 0, max_ending_here = 0; if (size > 0) { max_so_far = a[0]; max_ending_here = a[0]; } int i; for(i = 1; i < size; i++) { if (a[i - 1] < 0 && max_ending_here< 0) { max_ending_here = a[i]; } else { max_ending_here += a[i]; } /* Do not compare for all elements. Compare only when max_ending_here > 0 */ //else if (max_so_far < max_ending_here) max_so_far = max_ending_here; } return max_so_far; }Sorry,I forgot to remove comments as comments mentioned in post is irrelevant.
This code is working for negative numbers also. The array containing all negative numbers.
int getLargestSumContiguousSubarray (int *arr, int size ) { int i, max_so_far = *arr , max_end_here = *arr; for ( i = 1 ; i < size ; i ++ ) { max_end_here += arr[i] ; if ( max_end_here > max_so_far ) max_so_far = max_end_here ; if ( max_end_here < 0 ) max_end_here = 0 ; } return max_so_far ; }How to handle this case.. i want the starting and end position both....
-1 -2 -3 0 0 0 -4 -5 0 0 0 -9
a little modification to find start and end index of the subarray:
int max_sum(int *a,int n)
{
int max_so_far=0;
int max_ending_here=0;
int s,e;
s=e=-1;
for(i=0;i<=n-1;i++)
{
max_ending_here=max_ending_here+a[i];
if(max_ending_here<0)
{
max_ending_here=0;
s=i+1;
}
else if(max_so_far<max_ending_here)
{
max_so_far=max_ending_here;
e=i;
}
}
if(max_so_far==0)
{
s=-1;
e=-1;
}
}
This is not working for {1, 2}, start will be -1.
This solution will be ok:
int max_sum(int[] a, int n) {
int max_so_far = 0;
int max_ending_here = 0;
int s, e, largest;
s = e = largest = 0;
for (int i = 0; i a[largest]) largest = i;
max_ending_here = max_ending_here + a[i];
if (max_ending_here < 0) {
max_ending_here = 0;
s = i + 1;
} else if (max_so_far < max_ending_here) {
max_so_far = max_ending_here;
e = i;
}
}
if (a[largest] 0) ? max_so_far : a[largest];
}
DP approach to above problem:
http://anandtechblog.blogspot.com/2010/07/maximum-increasing-subsequence.html
The program is not working for {1,2,-1,3,4}
its returning 9 which is the sum of entire array. the expected result is 7
@Hill. 9 is the correct answer for your input array. The array itself is considered one of the subarrays of the array.
Input:
5 -2 8 3 -11 13 2 1 -1 0 3 8 -30 31 -4 3 -12
Max Ending Here:
5 3 11 14 3 16 18 19 18 18 21 29 -1(0) 31 27 30 18
Max_SoFar
--------------------------------29-------30 26 29 17
So is the answer 31 or 30 or 29?
It is 31.
This should work for all negatives case,without iterating the array more than once,so please verify it.
int maxSubArraySum(int a[],int size) { //note this algorithm does not work for all negative numbers int max_ending_here = 0,max_sum = 0; int i =0 ; int largest_num = 0x80000000; //the smallest integer if int's size is 4 bytes for(; i< size;i++) { if(a[i]>largest_num) largest_num = a[i]; max_ending_here += a[i]; //if is negative,recount the max_ending_here if(max_ending_here < 0) max_ending_here =0; else if(max_sum < max_ending_here) max_sum = max_ending_here; }//for return (largest_num > 0)?max_sum:largest_num; }sorry,the first comment line should be removed.
def max_subarray(A): max_so_far = max_ending_here = 0 for x in A: max_ending_here = max(0, max_ending_here + x) max_so_far = max(max_so_far, max_ending_here) return max_so_farCan somebody explain to me how is this algo DYNMAMIC PROGRAMMING ???????????
this is nothing except smart thinking
also can somebody give a dynamic programming solution for the problem ???
or even a recursive relation would do
@ravikant:
Refer to the below lines @http://en.wikipedia.org/wiki/Maximum_subarray_problem
"Because of the way this algorithm uses optimal substructures (the maximum subarray ending at each position is calculated in a simple way from a related but smaller and overlapping subproblem, the maximum subarray ending at the previous position) this algorithm can be viewed as a simple example of dynamic programming"
The below code is an example of top-down algorithm using recursion. It returns a value object that encapsulates (max-sum, lowerIndexOfSubArray, upperIndexOfSubArray).
public class MaximalSubArray { public static class MaxSubArrayVO { public int sum; public int lowerIndex; public int upperIndex; public MaxSubArrayVO(int sum, int lower, int upper) { this.sum = sum; this.lowerIndex = lower; this.upperIndex = upper; } public int range() { return upperIndex - lowerIndex; } } /** * Finds maximal-sub-array (sub-array whose sum is maximum) within the given input array of * +ve and -ve integers. It uses recursion and caches intermediate recursion results in a table (2-D array) * * @param array input array of +ve and -ve integers * @param startIndex lower index of the range of numbers to consider in the array * @param endIndex upper index of the range of numbers to consider in the array * @param maxSubArrayTable 2-D array that stores intermediate recursion results. * * @return maximal-sub-array-Value-Object that encapsulates (sum, lowerIndexOfSubArray, upperIndexOfSubArray). */ private static MaxSubArrayVO findMaximalSubArray(int[] array, int startIndex, int endIndex, MaxSubArrayVO[][] maxSubArrayTable) { if (endIndex < 0 || endIndex > array.length - 1 || startIndex < 0 || startIndex > array.length - 1) { return null; } // sub-array length = 1 if (endIndex == startIndex) { if (array[endIndex] > 0) { return new MaxSubArrayVO(array[startIndex], startIndex, startIndex); } else { // return 0 for a -ve number return new MaxSubArrayVO(0, startIndex, startIndex); } } // find maximal subarray in array-subset[startIndex, endIndex -1] if (maxSubArrayTable[startIndex][endIndex - 1] == null) { maxSubArrayTable[startIndex][endIndex - 1] = findMaximalSubArray( array, startIndex, endIndex - 1, maxSubArrayTable); } MaxSubArrayVO maxSubArrInSubsetOfArray = maxSubArrayTable[startIndex][endIndex - 1]; if (maxSubArrInSubsetOfArray != null && endIndex == (maxSubArrInSubsetOfArray.upperIndex + 1)) { // current element is contiguous to maxsubarray found in // array-subset[startIndex, endIndex -1] if (maxSubArrInSubsetOfArray.sum > 0) { int newSum = array[endIndex] + maxSubArrInSubsetOfArray.sum; if (newSum > 0) { return new MaxSubArrayVO(newSum, maxSubArrInSubsetOfArray.lowerIndex, endIndex); } else {// currentElement cannot be part of maxsubarray return maxSubArrInSubsetOfArray; } } else { // sum of maxsubarray in array-subset(startIndex -> // endIndex -1) is 0 or -ve if (array[endIndex] > 0) { return new MaxSubArrayVO(array[endIndex], endIndex, endIndex); } else { // return 0 for a -ve number return new MaxSubArrayVO(0, endIndex, endIndex); } } } else { // current element is NOT contiguous to maxsubarray in // array-subset[startIndex, endIndex -1] if (maxSubArrInSubsetOfArray.sum > 0) { if (array[endIndex] > maxSubArrInSubsetOfArray.sum) { // currentElement is larger than maxsubarray found so far return new MaxSubArrayVO(array[endIndex], endIndex, endIndex); } else { if (maxSubArrayTable[endIndex][array.length - 1] == null) { maxSubArrayTable[endIndex][array.length - 1] = findMaximalSubArray( array, endIndex, array.length - 1, maxSubArrayTable); } return max(maxSubArrayTable[endIndex][array.length - 1], maxSubArrInSubsetOfArray); } } else { // sum of array-subset[startIndex, endIndex -1] is 0 or // -ve if (array[endIndex] > 0) { return new MaxSubArrayVO(array[endIndex], endIndex, endIndex); } else { // return 0 for a -ve number return new MaxSubArrayVO(0, endIndex, endIndex); } } } } /** * Returns subarrayVO whose sum is maximum; if sum is equal, then longer * subarray gets preference. */ private static MaxSubArrayVO max(MaxSubArrayVO sub1, MaxSubArrayVO sub2) { return sub1.sum > sub2.sum ? sub1 : ((sub1.sum == sub2.sum) && (sub1 .range() > sub2.range())) ? sub1 : sub2; } /** * @param args */ public static void main(String[] args) { // input array int[] array = new int[] { 6, 4, -11, 7, 6, -2, 0, -15, -1, -3, 25, 2, -3, 4 }; // table that caches intermediate results; [i][j] denote the range of // subarray MaxSubArrayVO[][] maxSubArrayTable = new MaxSubArrayVO[array.length][array.length]; MaxSubArrayVO maxSubArrVO = findMaximalSubArray(array, 0, array.length - 1, maxSubArrayTable); System.out.println("Max sum = " + maxSubArrVO.sum); System.out.println("lower index = " + maxSubArrVO.lowerIndex); System.out.println("upper Index = " + maxSubArrVO.upperIndex); } }omg, the above code was in java and the formatting has gone for a toss
I tried to edit it later but didn't find this feature. Apologies to the folks...
why doesnt input a[] = {-2, -3, 4, -4, 50, 5, -3};
work in kadane's algorithm
it gives me output as 2293724
Check you array size parameter.
I added your test array and got 55.
int arrAravind_Sen[] = {-2, -3, 4, -4, 50, 5, -3}; max = testCaseHelper(arrAravind_Sen,(sizeof(arrAravind_Sen)/sizeof(int)), 55);thanks..
What if all elements in the array are negative. Will it not return 0 in this case which is wrong?
Correct me if I am missing something
Possible solution for an array input with all negative numbers:
// initialize max_so_far to the first element of the array
max_so_far = a[0];
{ -1, -20, -4, -5 } returns -1
{ -10, -5, -3, -2 } returns -2
Initializing max_so_far to the first element of the array might not work as we also have below condition in the code.
You are correct. So along with the initialization code. I modified the following code:
// guarantee an array of at least one element if(a == 0) return 0; if(size < 1) return 0; max_so_far = a[0]; ... //if(max_ending_here < 0) // max_ending_here = 0; // condition to start a new subarray to sum if(max_ending_here < a[i]) max_ending_here = a[i]; result of test cases so far: /* testCase: arr= 0 max = 0 passed testCase: arr= -99 max = -99 passed testCase: arr= 34 max = 34 passed testCase: arr= 0 1 2 3 4 5 max = 15 passed testCase: arr= 99 1 10 2 4 max = 116 passed testCase: arr= 34 0 1 12 10 max = 57 passed testCase: arr= 1 -9 4 5 6 -1 2 max = 16 passed testCase: arr= 1 -9 4 5 6 -10 2 max = 15 passed testCase: arr= 1 -9 4 5 6 -16 45 max = 45 passed testCase: arr= 1 -9 4 5 6 -10 45 max = 50 passed testCase: arr= -1 -9 -2 -3 -4 -5 0 max = 0 passed testCase: arr= -99 -1 -10 -2 -4 max = -1 passed testCase: arr= -34 -5 -1 -12 -1 max = -1 passed */The test cases above do not cover all cases, but it looks promising.
Following code works for all cases. I think checking for max_present<0, is needed here.
#include <iostream>
using namespace std;
int main() {
int arr[]={-2,-3,4,-1,-2,-7,-5,-3};
int max_present,max_all,i;
max_present=0;
max_all=arr[0];
for(i=0;i<8;i++)
{
max_present+=arr[i];
if(max_all<max_present){
max_all=max_present;
}
if(max_present<0){
max_present=0;
}
}
cout<<"Max sum is "<<max_all;
return 0;
}
In this example {-2, -3, 4, -1, -2, 1, 5, -3}..shouldn't 6 be the answer (1 and 5)...we're getting 4 which i feel isn't correct. Please correct me if I'm wrong.
@Asit: The program doesn't return 4, it returns 7 (4 + -1 + -2 + 1 + 5). In function maxSubArraySum(), we return max_so_far, not max_ending_here (whose final value is 4).
Sorry, my mistake.I considered max_ending_here instead of max_so_far
uh... I think there's a typo in the example? The critical 6th index reads:
for i=6, a[6] = 1
... etc ...
The element at a[6] is 5, not 1. The rest of the statement it correct, but that assignment error might be confusing to a non-programmer trying to understand the explanation of algorithm? I've been programming for a while, and I still did a triple take until I found the typo.
Or, is this a test to see if the readers can debug pseudo-code?
@ab: Thanks for pointing this out. We have corrected the typo.
@Hary: Your solution works fine.
One thing to add - When count of negative numbers is odd, we need to check product of left and right for both first and last negative elements. So we need to get max of these four products.
Thanks for writing the solution. Keep writing to us!
Here is the code as discussed by you and Hary.
#include<stdio.h> int max(int a, int b) { int max_num; return (a>b ? a:b); } int maxSubArrayProd(int a[], int size) { int max_so_far = 1; int i; //stores number of negative entries int num_of_neg=0; //stores first negative entries if any int first_neg; //stores last negative entries if any int last_neg; int prod_so_far_right_of_last_neg=1; int prod_so_far_left_for_first_neg=1; int prod_so_far_left=1; int prod_so_far_right=1; int prod_so_far_middle=1; int prod_right_of_last_neg=1; int prod_left_of_last_neg=1; int prod_left_of_first_neg=1; int prod_right_of_first_neg=1; for(i = 0; i < size; i++) { if (a[i] < 0) { if (num_of_neg == 0) { first_neg = i; } num_of_neg++; last_neg = i; } } if ((num_of_neg%2 == 0) || (num_of_neg == 0)) { //multiply all for(i = 0; i < size; i++) { max_so_far *= a[i]; } return max_so_far; } else if (num_of_neg == 1) { //only one negative number //find prod of left and write numbers for(i = 0; i < first_neg; i++) { prod_so_far_left *= a[i]; } for(i = first_neg+1; i < size; i++) { prod_so_far_right *= a[i]; } return max(prod_so_far_left, prod_so_far_right); } else { //more than one odd negative numbers for(i = 0; i < first_neg; i++) { prod_so_far_left_for_first_neg *= a[i]; } for(i = first_neg+1; i < last_neg; i++) { prod_so_far_middle *= a[i]; } for(i = last_neg+1; i < size; i++) { prod_so_far_right_of_last_neg *= a[i]; } prod_left_of_first_neg = prod_so_far_left_for_first_neg; prod_right_of_first_neg = prod_so_far_middle * prod_so_far_right_of_last_neg * a[last_neg]; prod_left_of_last_neg = prod_so_far_left_for_first_neg * a[first_neg] * prod_so_far_middle; prod_right_of_last_neg = prod_so_far_right_of_last_neg; return (max(max(prod_right_of_last_neg, prod_left_of_last_neg), max(prod_right_of_first_neg, prod_left_of_first_neg))); } } /*Driver program to test maxSubArraySum*/ int main() { int a[] = {-2, -3, 4, -1, -2, 1, 5, -3}; int max_prod = maxSubArrayProd(a, 8); printf("Maximum contiguous prod is %d\n", max_prod); return 0; }what if 0 is one of the element
Ok, as far as the all negative and all positive are concerned
you dont have to worry because in case of all positive - just add the entire array to get the result - in case of all negative - just find out the smalles no in terms of magnitude.
The problem becomes sensible only when you have a blend of negative and positive nos.
As far as the "product variant" of this ques is listed above:
I would say just find out the no of negative elements. If they are even, find the product of all the nos in the array , If the no of negative elements is odd then scan the array to find the last negative element. Find out the product of all the elements on one side of it - call it product left - and similarly for all the elements on the right of it - call them product right.
Yield which ever is greater .
Please correct me if i am missing something
Hi Raj, as mentioned in the notes, the algorithm doesn't work for all negative numbers.
For handling this we can add an extra phase before actual implementation. The phase will look if all numbers are negative, if they are it will return maximum of them (or smallest in terms of absolute value). There may be other ways to handle it though.
Thanks for the comment, keep visiting us.
what if all the input values are negative.
EX: {-2, -3, -4, -1, -2, -1, -5, -3}
Possible solution for an array input with all negative numbers:
max_so_far = a[0];
// initialize to the first element of the array
{ -1, -20, -4, -5 } returns -1
{ -10, -5, -3, -2 } returns -2