Dynamic Programming | Set 27 (Maximum sum rectangle in a 2D matrix)
Given a 2D array, find the maximum sum subarray in it. For example, in the following 2D array, the maximum sum subarray is highlighted with blue rectangle and sum of this subarray is 29.
This problem is mainly an extension of Largest Sum Contiguous Subarray for 1D array.
The naive solution for this problem is to check every possible rectangle in given 2D array. This solution requires 4 nested loops and time complexity of this solution would be O(n^4).
Kadane’s algorithm for 1D array can be used to reduce the time complexity to O(n^3). The idea is to fix the left and right columns one by one and find the maximum sum contiguous rows for every left and right column pair. We basically find top and bottom row numbers (which have maximum sum) for every fixed left and right column pair. To find the top and bottom row numbers, calculate sun of elements in every row from left to right and store these sums in an array say temp[]. So temp[i] indicates sum of elements from left to right in row i. If we apply Kadane’s 1D algorithm on temp[], and get the maximum sum subarray of temp, this maximum sum would be the maximum possible sum with left and right as boundary columns. To get the overall maximum sum, we compare this sum with the maximum sum so far.
// Program to find maximum sum subarray in a given 2D array
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define ROW 4
#define COL 5
// Implementation of Kadane's algorithm for 1D array. The function returns the
// maximum sum and stores starting and ending indexes of the maximum sum subarray
// at addresses pointed by start and finish pointers respectively.
int kadane(int* arr, int* start, int* finish, int n)
{
// initialize sum, maxSum and start
int sum = 0, maxSum = INT_MIN, i;
// needed if sum NEVER becomes less than 0
*start = 0;
// Standard Kadane's algorithm. See following link
// http://www.geeksforgeeks.org/largest-sum-contiguous-subarray/
for (i = 0; i < n; ++i)
{
sum += arr[i];
if (sum < 0)
{
sum = 0;
*start = i+1;
}
else if (sum > maxSum)
{
maxSum = sum;
*finish = i;
}
}
return maxSum;
}
// The main function that finds maximum sum rectangle in M[][]
void findMaxSum(int M[][COL])
{
// Variables to store the final output
int maxSum = 0, finalLeft, finalRight, finalTop, finalBottom;
int left, right, i;
int temp[ROW], sum, start, finish;
// Set the left column
for (left = 0; left < COL; ++left)
{
// Initialize all elements of temp as 0
memset(temp, 0, sizeof(temp));
// Set the right column for the left column set by outer loop
for (right = left; right < COL; ++right)
{
// Calculate sum between current left and right for every row 'i'
for (i = 0; i < ROW; ++i)
temp[i] += M[i][right];
// Find the maximum sum subarray in temp[]. The kadane() function
// also sets values of start and finish. So 'sum' is sum of
// rectangle between (start, left) and (finish, right) which is the
// maximum sum with boundary columns strictly as left and right.
sum = kadane(temp, &start, &finish, ROW);
// Compare sum with maximum sum so far. If sum is more, then update
// maxSum and other output values
if (sum > maxSum)
{
maxSum = sum;
finalLeft = left;
finalRight = right;
finalTop = start;
finalBottom = finish;
}
}
}
// Print final values
printf("(Top, Left) (%d, %d)\n", finalTop, finalLeft);
printf("(Bottom, Right) (%d, %d)\n", finalBottom, finalRight);
printf("Max sum is: %d\n", maxSum);
}
// Driver program to test above functions
int main()
{
int M[ROW][COL] = {{1, 2, -1, -4, -20},
{-8, -3, 4, 2, 1},
{3, 8, 10, 1, 3},
{-4, -1, 1, 7, -6}
};
findMaxSum(M);
return 0;
}
Output:
(Top, Left) (1, 1) (Bottom, Right) (3, 3) Max sum is: 29
Time Complexity: O(n^3)
This article is compiled by Aashish Barnwal. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Given a matrix of both +ve and -ve numbers, find out the maximum sum sub matrix. First of all we will calculate the sum matrix where s[i][j] = sum of all the elements from [0,0] to [i,j] int s[ROW][COL]; void computeSumMatrix(int a[][COL], int r, int c) { for (int i = 0; i < r; i++) if (i == 0) s[i][0] = a[i][0]; else s[i][0] = s[i - 1][0] + a[i][0]; for (int j = 0; j < c; j++) if (j == 0) s[0][j] = a[0][j]; else s[0][j] = s[0][j - 1] + a[0][j]; for (int i = 1; i < r; i++) { for (int j = 1; j < c; j++) { s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; } } Now we will write a method to get the sum of a sub matrix given upper-left (r1,c1) indexes and lower-bottom (r2,c2) indexes int getSubmatSum(int r1, int c1, int r2, int c2) { if (r1 == 0 && c1 == 0) return s[r2][c2]; if (r1 == 0) return s[r2][c2] - s[r2][c1 - 1]; if (c1 == 0) return s[r2][c2] - s[r1 - 1][c2]; return s[r2][c2] - s[r1 - 1][c2] - s[r2][c1 - 1] + s[r1 - 1][c1 - 1]; } Using both these methods, we can iterate through all the possible sub matrices and get their sum in O(1). To iterate though all the possible sub-matrices would take O(n^4). int getMaxSubmatSum(int a[][COL], int r, int c) { int maxsum = 0; for (int r1 = 0; r1 < r; r1++) { for (int c1 = 0; c1 < c; c1++) { for (int r2 = r1; r2 < r; r2++) { for (int c2 = c1; c2 < c; c2++) { int sum = getSubmatSum(r1, c1, r2, c2); maxsum = max(sum, maxsum); } } } } return maxsum; } Now, we are going to optimize this solution to O(n^3). The trick is to apply Kadane's algorithm on a 2D matrix. We will consider all the possible 2D matrices which are starting from 0th column and treat them as 1D arrays. int getMaxSubmatSum2(int a[][COL], int r, int c) { int globalmax = 0; for (int i = 0; i < r; i++) for (int j = i; j < r; j++) { int localmax = 0; for (int k = 0; k < c; k++) { localmax = max(localmax + getSubmatSum(i, k, j, k), 0); globalmax = max(localmax, globalmax); } } return globalmax; } Source is : http://geekmeal.blogspot.in/2013/02/syntaxhighlighter.htmlThe lines
// Calculate sum between current left and right for every row 'i' for (i = 0; i < ROW; ++i) temp[i] += M[i][right];is wrong.
We should calculate temp[i] = M[i][left] + ... + M[i][right]
which should be done in a loop.
for (i = 0; i < ROW; ++i) for(int j = left; j <=right; j++) temp[i] += M[i][j];I think I got the point. Please ignore my previous comment.
In the first iteration when right=left, there is only 1 column in temp per i.
temp[i] = 0 (temp is initialized to 0) + M[i][right or left, its same in first iteration]
In 2nd iteration, when right=left+1,
temp[i] = old_temp[i] (which is M[i][left]) + M[i][right]
Intelligent
Your kadance method wont work to find start and finish index when given 2d matrix contains only negative integers.
So given solution will be wrong.
How is the naive solution O(n^4) ?
Shouldn't it be O(n^6) if we are checking all the possible rectangles ?
O(n^2) for choosing the start point and O(n^2) for choosing the end point i.e. 4 loops and then to calculate the sum another two for loops ?
there is a O(n^2) solution with O(n^2) space complexity.
Algo :
1. Create another matrix of the same size mat[R][C].
2. Fill the mat[R][C] such that mat[i][j] contains the sum of the matrix M from [0,0] to [i,j]. Complexity n^2. something similar to kadane's algo.
3. Now run two loops for i and j .. like the above post , but now you don't need to find the sum in O(n) time as you can find it from previously constructed mat in constant time. How ?
for start position, you need n^2;
and for end position, you also need n^2.
so is that n^4?
I mean O(n^2) time
O(n^2) time
and O(n^4) time
this part is wrong ,start will be updated even though if the start is not a part of maximum sum
for (i = 0; i < n; ++i) { sum += arr[i]; if (sum < 0) { sum = 0; *start = i+1; } else if (sum > maxSum) { maxSum = sum; *finish = i; } }hai da BR....
you should rename the variable start to localstart
else if (sum > maxSum)
{ maxSum = sum;
*finish = i;
*start = localstart;
}
otherwise your start will be modified everytime the sum upto current point from previous start is -ve, note that this is not the starting point for max contiguous sum.
Should the complexity not be O(n4) as Kadane's itself is O(n).
No,because your could do the sum of row in a growing manner.
say you want to calculate any combination of columns start from 1,
1--> col[] = column 1 's value
2--> add column 1's value to col[] and you get column 1-2's sum
and so on.
So the for i=0..n-1, for j=i..n takes O(n^2)
and each iteration takes O(n) to calculate the best range sum.
But look - say you have 2D array 3x3.
The structure is:
for loop1(for loop2(for loop3, for loop4))
First, the most outer one will be done 3 times. The second - for the first time 3 times, then 2, then 1. The third AND the fourth will be done the same amount of times - 3.
So it's like this:
3 -> 3+3 - 6 times during each loop, gives us 18.
2 -> 3+3 - 18 + 12 = 30
1 -> 3+3 - 30 + 6 = 36.
n^3 = 27; 36 > 27.
I'll try to figure out if there's a way to connect both loops... Of course my thinking might be wrong (I hope it is), if there's an error in how I think, please respond.
Well, anyway, I corrected my code and it's definitely n^3 now. Actually, no, it's even less.