Open In App

Maximum sum rectangle in a 2D matrix

Last Updated : 28 Jul, 2025
Suggest changes
Share
128 Likes
Like
Report

Given a 2D matrix mat[][] of integers, find the submatrix (i.e., a rectangular section of the matrix) that has the maximum possible sum among all possible submatrices.

Example:

Input: mat[][] = [[1, 2, -1, -4, -20],
[-8, -3, 4, 2, 1],
[3, 8, 10, 1, 3],
[-4, -1, 1, 7, -6]]
Output: 29
Explanation: The matrix is as follows and the green rectangle denotes the maximum sum rectangle which is equal to 29.

maximum---------sum---------rectangle---------in---------a---------2d---------matrix---------3

This problem is mainly an extension of the Maximum Subarray Sum.

[Naive approach] Iterating Over All Possible Submatrices

We explore all possible rectangles in the given 2D array, by using four variables: two to define the left and right boundaries and two more to define the top and bottom boundaries and calculate their sums, and keep track of the maximum sum found.

C++
#include <iostream> #include <vector> #include <climits> using namespace std; int maxRectSum(vector<vector<int>> &mat) {    int n = mat.size();  int m = mat[0].size();  int maxSum = INT_MIN;  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m; right++) {    // Find the sum of submatrix(up, right, down, left)  int sum = 0;  for (int i = up; i <= down; i++) {  for (int j = left; j <= right; j++) {  sum += mat[i][j];  }  }  // Update maxSum if sum > maxSum.  if (sum > maxSum) {  maxSum = sum;  }  }  }  }  }  return maxSum; } int main() {  vector<vector<int>> mat = {{1, 2, -1, -4, -20},   {-8, -3, 4, 2, 1},   {3, 8, 10, 1, 3},   {-4, -1, 1, 7, -6}};    cout << maxRectSum(mat) << endl;  return 0; } 
Java
class GfG {  static int maxRectSum(int[][] mat) {  int n = mat.length;  int m = mat[0].length;  int maxSum = Integer.MIN_VALUE;  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m; right++) {    // Find the sum of  // submatrix(up, right, down, left)  int sum = 0;  for (int i = up;  i <= down; i++) {  for (int j = left;  j <= right; j++) {  sum += mat[i][j];  }  }  // Update maxSum if sum > maxSum.  if (sum > maxSum) {  maxSum = sum;  }  }  }  }  }  return maxSum;  }  public static void main(String[] args) {  int[][] mat = { { 1, 2, -1, -4, -20 },  { -8, -3, 4, 2, 1 },  { 3, 8, 10, 1, 3 },  { -4, -1, 1, 7, -6 } };  System.out.println(maxRectSum(mat));  } } 
Python
def maxRectSum(mat): n = len(mat) m = len(mat[0]) maxSum = float('-inf') for up in range(n): for left in range(m): for down in range(up, n): for right in range(left, m): # Calculate the sum of submatrix  # (up, left, down, right) subMatrixSum = 0 for i in range(up, down + 1): for j in range(left, right + 1): subMatrixSum += mat[i][j] # Update maxSum if a larger sum is found maxSum = max(maxSum, subMatrixSum) return maxSum if __name__ == "__main__": mat = [ [1, 2, -1, -4, -20], [-8, -3, 4, 2, 1], [3, 8, 10, 1, 3], [-4, -1, 1, 7, -6] ] print(maxRectSum(mat)) 
C#
using System; class GfG {  static int maxRectSum(int[][] mat) {  int n = mat.Length;  int m = mat[0].Length;  int maxSum = int.MinValue;  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m; right++) {    // Calculate the sum of submatrix   // (up, left, down, right)  int subMatrixSum = 0;  for (int i = up; i <= down; i++) {  for (int j = left; j <= right; j++) {  subMatrixSum += mat[i][j];  }  }  // Update maxSum if a larger sum is found  maxSum = Math.Max(maxSum, subMatrixSum);  }  }  }  }  return maxSum;  }  static void Main(string[] args) {  int[][] mat = {   new int[] { 1, 2, -1, -4, -20 },  new int[] { -8, -3, 4, 2, 1 },  new int[] { 3, 8, 10, 1, 3 },  new int[] { -4, -1, 1, 7, -6 }   };  Console.WriteLine(maxRectSum(mat));   } } 
JavaScript
function maxRectSum(mat) {  const n = mat.length;  const m = mat[0].length;  let maxSum = -Infinity;  for (let up = 0; up < n; up++) {  for (let left = 0; left < m; left++) {  for (let down = up; down < n; down++) {  for (let right = left; right < m; right++) {    // Calculate the sum of submatrix   // (up, left, down, right)  let subMatrixSum = 0;  for (let i = up; i <= down; i++) {  for (let j = left; j <= right; j++) {  subMatrixSum += mat[i][j];  }  }  // Update maxSum if a larger sum is  // found  maxSum = Math.max(maxSum, subMatrixSum);  }  }  }  }  return maxSum; } // Driver Code const mat = [  [ 1, 2, -1, -4, -20 ],   [ -8, -3, 4, 2, 1 ],  [ 3, 8, 10, 1, 3 ],   [ -4, -1, 1, 7, -6 ] ]; console.log(maxRectSum(mat)); 

Time Complexity: O((n*m)3), as we iterate over all the boundaries of the rectangle in O((n*m)2) time. For each rectangle, we find its sum in O(n*m) time.
Auxiliary Space: O(1)

[Better Approach] Using Prefix Sum

In this approach, we used prefix sum matrix to efficiently compute the sum of any submatrix. We first precompute the prefix sum such that pref[i][j] stores the sum of all elements in the submatrix from the top-left corner (0, 0) to the cell (i, j). This preprocessing allows us to calculate the sum of any arbitrary submatrix in constant time using the inclusion-exclusion principle, thereby eliminating redundant computations and significantly improving performance.

Step by Step Approach:

  • Initialize a 2D prefix sum matrix pref[][] of the same size as the input matrix.
  • Precompute the prefix sum for each cell : pref[i][j] = matrix[i][j] + pref[i−1][j] + pref[i][j−1] − pref[i−1][j−1] (Handle edges separately to avoid index out-of-bound errors.)
  • Iterate over all possible top-left corners (up, left) and bottom-right corners (down, right) to define submatrices.
  • For each such submatrix, compute the sum using the prefix sum matrix in constant time: sum = pref[down][right] − pref[up - 1][right] − pref[down][left−1] + pref[up-1][left - 1]
  • Track the maximum sum obtained across all submatrices.
C++
#include <iostream> #include <vector> #include <climits> using namespace std; int findSum(int up, int left, int down, int right,   vector<vector<int>> &pref) {    // Start with the sum of the entire submatrix (0, 0) to (down, right)  int sum = pref[down][right];   // Subtract the area to the left of the submatrix, if it exists  if (left - 1 >= 0) {  sum -= pref[down][left - 1];  }  // Subtract the area above the submatrix, if it exists  if (up - 1 >= 0) {  sum -= pref[up - 1][right];  }  // Add back the overlapping area that was subtracted twice  if (up - 1 >= 0 && left - 1 >= 0) {  sum += pref[up - 1][left - 1];  }  return sum; } // function to find the maximum sum rectangle in a 2D matrix int maxRectSum(vector<vector<int>> &mat) {  int n = mat.size();  int m = mat[0].size();  // Initialize the prefix sum matrix  vector<vector<int>> pref(n, vector<int>(m, 0));  // Row-wise sum  for (int i = 0; i < n; i++) {  for (int j = 0; j < m; j++) {  pref[i][j] = mat[i][j];  if (j - 1 >= 0) {  pref[i][j] += pref[i][j - 1];  }  }  }  // Column-wise sum  for (int j = 0; j < m; j++) {  for (int i = 0; i < n; i++) {  if (i - 1 >= 0) {  pref[i][j] += pref[i - 1][j];  }  }  }  int maxSum = INT_MIN;  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m; right++) {    // Find the sum of submatrix(up, right, down, left)  int sum = findSum(up, left, down, right, pref);  // Update maxSum if sum > maxSum.  if (sum > maxSum) {  maxSum = sum;  }  }  }  }  }  return maxSum; } int main() {  vector<vector<int>> mat = {{1, 2, -1, -4, -20},   {-8, -3, 4, 2, 1},   {3, 8, 10, 1, 3},   {-4, -1, 1, 7, -6}};  cout << maxRectSum(mat) << endl; } 
Java
import java.util.*; class GfG {    static int findSum(int up, int left, int down, int right,  int[][] pref) {  // Start with the sum of the entire submatrix   // (0, 0) to (down, right)  int sum = pref[down][right];    // Subtract the area to the left of the submatrix, if it exists  if (left - 1 >= 0) {  sum -= pref[down][left - 1];  }    // Subtract the area above the submatrix, if it exists  if (up - 1 >= 0) {  sum -= pref[up - 1][right];  }    // Add back the overlapping area that was subtracted twice  if (up - 1 >= 0 && left - 1 >= 0) {  sum += pref[up - 1][left - 1];  }    return sum;  }  // function to find the maximum sum rectangle in a 2D matrix  public static int maxRectSum(int[][] mat) {  int n = mat.length;  int m = mat[0].length;  // Initialize the prefix sum matrix  int[][] pref = new int[n][m];  // Row-wise sum  for (int i = 0; i < n; i++) {  for (int j = 0; j < m; j++) {  pref[i][j] = mat[i][j];  if (j - 1 >= 0) {  pref[i][j] += pref[i][j - 1];  }  }  }  // Column-wise sum  for (int j = 0; j < m; j++) {  for (int i = 0; i < n; i++) {  if (i - 1 >= 0) {  pref[i][j] += pref[i - 1][j];  }  }  }  // Find the maximum sum rectangle  int maxSum = Integer.MIN_VALUE;  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m;  right++) {  // Find the sum of the submatrix  // (up, left) to  // (down, right)  int sum = findSum( up, left, down,   right, pref);  // Update maxSum if sum > maxSum  if (sum > maxSum) {  maxSum = sum;  }  }  }  }  }  return maxSum;  }  public static void main(String[] args) {  int[][] mat = { { 1, 2, -1, -4, -20 },  { -8, -3, 4, 2, 1 },  { 3, 8, 10, 1, 3 },  { -4, -1, 1, 7, -6 } };  System.out.println(maxRectSum(mat));  } } 
Python
def findSum(up, left, down, right, pref): # Start with the sum of the entire submatrix (0, 0) to (down, right) totalSum = pref[down][right] # Subtract the area to the left of the submatrix, if it exists if left - 1 >= 0: totalSum -= pref[down][left - 1] # Subtract the area above the submatrix, if it exists if up - 1 >= 0: totalSum -= pref[up - 1][right] # Add back the overlapping area that was subtracted twice if up - 1 >= 0 and left - 1 >= 0: totalSum += pref[up - 1][left - 1] return totalSum # Function to find the maximum sum rectangle in a 2D matrix def maxRectSum(mat): n = len(mat) m = len(mat[0]) # Initialize the prefix sum matrix pref = [[0] * m for _ in range(n)] # Row-wise sum for i in range(n): for j in range(m): pref[i][j] = mat[i][j] if j - 1 >= 0: pref[i][j] += pref[i][j - 1] # Column-wise sum for j in range(m): for i in range(n): if i - 1 >= 0: pref[i][j] += pref[i - 1][j] # Find the maximum sum rectangle maxSum = float('-inf') for up in range(n): for left in range(m): for down in range(up, n): for right in range(left, m): totalSum = findSum(up, left, down, right, pref) maxSum = max(maxSum, totalSum) return maxSum if __name__ == "__main__": mat = [ [1, 2, -1, -4, -20], [-8, -3, 4, 2, 1], [3, 8, 10, 1, 3], [-4, -1, 1, 7, -6] ] print(maxRectSum(mat)) 
C#
using System; class GfG {  static int findSum(int up, int left, int down, int right, int[,] pref) {  // Start with the sum of the entire submatrix from (0,0) to (down,right)  int sum = pref[down, right];  // Subtract the area to the left of the submatrix, if it exists  if (left - 1 >= 0)  sum -= pref[down, left - 1];  // Subtract the area above the submatrix, if it exists  if (up - 1 >= 0)  sum -= pref[up - 1, right];  // Add back the overlapping area that was subtracted twice  if (up - 1 >= 0 && left - 1 >= 0)  sum += pref[up - 1, left - 1];  return sum;  }  static int maxRectSum(int[,] mat) {  int n = mat.GetLength(0);  int m = mat.GetLength(1);  // Initialize the prefix sum matrix  int[,] pref = new int[n, m];  // Compute row-wise prefix sum  for (int i = 0; i < n; i++) {  for (int j = 0; j < m; j++) {  pref[i, j] = mat[i, j];  if (j - 1 >= 0)  pref[i, j] += pref[i, j - 1];  }  }  // Compute column-wise prefix sum  for (int j = 0; j < m; j++) {  for (int i = 0; i < n; i++) {  if (i - 1 >= 0)  pref[i, j] += pref[i - 1, j];  }  }  int maxSum = int.MinValue;  // Check all possible submatrices  for (int up = 0; up < n; up++) {  for (int left = 0; left < m; left++) {  for (int down = up; down < n; down++) {  for (int right = left; right < m; right++) {  int totalSum = findSum(up, left, down, right, pref);  if (totalSum > maxSum)  maxSum = totalSum;  }  }  }  }  return maxSum;  }  static void Main(string[] args) {  int[,] mat = new int[,]  {  { 1, 2, -1, -4, -20 },  { -8, -3, 4, 2, 1 },  { 3, 8, 10, 1, 3 },  { -4, -1, 1, 7, -6 }  };  Console.WriteLine(maxRectSum(mat));   } } 
JavaScript
// Function to get the sum of submatrix (r1, c1) to (r2, c2) function findSum(up, left, down, right, pref) {    // Start with the sum of the entire submatrix (0, 0) to (down, right)  let sum = pref[down][right];   // Subtract the area to the left of the submatrix, if it exists  if (left - 1 >= 0) {  sum -= pref[down][left - 1];  }  // Subtract the area above the submatrix, if it exists  if (up - 1 >= 0) {  sum -= pref[up - 1][right];  }  // Add back the overlapping area that was subtracted twice  if (up - 1 >= 0 && left - 1 >= 0) {  sum += pref[up - 1][left - 1];  }  return sum; } // function to find the maximum sum rectangle in a 2D matrix function maxRectSum(mat) {  const n = mat.length;  const m = mat[0].length;  // Create and initialize prefix sum matrix  const pref = Array.from({ length: n }, () => Array(m).fill(0));  // Row-wise prefix sum  for (let i = 0; i < n; i++) {  for (let j = 0; j < m; j++) {  pref[i][j] = mat[i][j];  if (j - 1 >= 0) {  pref[i][j] += pref[i][j - 1];  }  }  }  // Column-wise prefix sum  for (let j = 0; j < m; j++) {  for (let i = 0; i < n; i++) {  if (i - 1 >= 0) {  pref[i][j] += pref[i - 1][j];  }  }  }  let maxSum = -Infinity;  // Try all submatrices  for (let up = 0; up < n; up++) {  for (let left = 0; left < m; left++) {  for (let down = up; down < n; down++) {  for (let right = left; right < m; right++) {  let sum = findSum(up, left, down, right, pref);  if (sum > maxSum) {  maxSum = sum;  }  }  }  }  }  return maxSum; } // Driver code const mat = [  [ 1, 2, -1, -4, -20 ],  [ -8, -3, 4, 2, 1 ],  [ 3, 8, 10, 1, 3 ],  [ -4, -1, 1, 7, -6 ] ]; console.log(maxRectSum(mat)); // Output: 29 

Time Complexity: O((n*m)2)
Auxiliary Space: O(n*m), due to the prefix sum matrix.

[Expected Approach] Using Kadane’s Algorithm

Instead of checking every possible submatrix, we fix two column boundaries: left and right. For each pair of columns, we compress the 2D matrix into a 1D array, where each element represents the sum of rows between the current left and right columns. This 1D array (temp[]) represents the column-wise sum for a fixed column window.
Now, we can apply Kadane’s algorithm on this temp[] array to find the maximum subarray sum, which corresponds to a rectangular submatrix with the maximum sum between columns left and right.

C++
#include <iostream> #include <vector> #include <climits> using namespace std; // Kadane's algorithm to find the maximum sum  // subarray in a 1D array int kadane(vector<int>& temp) {  int rows = temp.size();  int currSum = 0;  int maxSum = INT_MIN;  for (int i = 0; i < rows; i++) {  currSum += temp[i];  // Update maxSum if the current sum is greater  if (maxSum < currSum) {  maxSum = currSum;  }  // If the current sum becomes negative, reset it to 0  if (currSum < 0) {  currSum = 0;  }  }  return maxSum; } // Function to find the maximum sum rectangle in a 2D matrix int maxRectSum(vector<vector<int>> &mat) {  int rows = mat.size();  int cols = mat[0].size();  int maxSum = INT_MIN;  // Initialize a temporary array to store row-wise  // sums between left and right boundaries  vector<int> temp(rows);  // Check for all possible left and right boundaries  for (int left = 0; left < cols; left++) {    // Reset the temporary array for each new left boundary  for (int i = 0; i < rows; i++)  temp[i] = 0;  for (int right = left; right < cols; right++) {    // Update the temporary array with the current  // column's values  for (int row = 0; row < rows; row++) {  temp[row] += mat[row][right];  }  // Find the maximum sum of the subarray for the   // current column boundaries  int sum = kadane(temp);  // Update the maximum sum found so far  maxSum = max(maxSum, sum);  }  }  return maxSum; } int main() {  vector<vector<int>> mat = {{1, 2, -1, -4, -20},  {-8, -3, 4, 2, 1},   {3, 8, 10, 1, 3},  {-4, -1, 1, 7, -6}};  int res = maxRectSum(mat);   cout << res << endl;   return 0; } 
Java
class GfG {  // Kadane's algorithm to find the maximum sum subarray  // in a 1D array  static int kadane(int[] temp) {  int rows = temp.length;  int currSum = 0;  int maxSum = Integer.MIN_VALUE;  for (int i = 0; i < rows; i++) {  currSum += temp[i];  // Update maxSum if the current sum is greater  if (maxSum < currSum) {  maxSum = currSum;  }  // If the current sum becomes negative, reset it  // to 0  if (currSum < 0) {  currSum = 0;  }  }  return maxSum;  }  // Function to find the maximum sum rectangle in a 2D  // matrix  static int maxRectSum(int[][] mat) {  int rows = mat.length;  int cols = mat[0].length;  int maxSum = Integer.MIN_VALUE;  // Initialize a temporary array to store row-wise  // sums between left and right boundaries  int[] temp = new int[rows];  // Check for all possible left and right boundaries  for (int left = 0; left < cols; left++) {    // Reset the temporary array for each new left  // boundary  for (int i = 0; i < rows; i++) {  temp[i] = 0;  }  for (int right = left; right < cols; right++) {    // Update the temporary array with the  // current column's values  for (int row = 0; row < rows; row++) {  temp[row] += mat[row][right];  }  // Find the maximum sum of the subarray for  // the current column boundaries  int sum = kadane(temp);  // Update the maximum sum found so far  maxSum = Math.max(maxSum, sum);  }  }  return maxSum;  }  public static void main(String[] args) {  int[][] mat = { { 1, 2, -1, -4, -20 },  { -8, -3, 4, 2, 1 },  { 3, 8, 10, 1, 3 },  { -4, -1, 1, 7, -6 } };  int res = maxRectSum(mat);  System.out.println(res);  } } 
Python
def kadane(temp): rows = len(temp) currSum = 0 maxSum = float('-inf') for i in range(rows): currSum += temp[i] # Update maxSum if the current sum is greater if maxSum < currSum: maxSum = currSum # If the current sum becomes negative, reset it to 0 if currSum < 0: currSum = 0 return maxSum def maxRectSum(mat): rows = len(mat) cols = len(mat[0]) maxSum = float('-inf') # Initialize a temporary array to store row-wise # sums between left and right boundaries temp = [0] * rows # Check for all possible left and right boundaries for left in range(cols): # Reset the temporary array for each new left # boundary temp = [0] * rows for right in range(left, cols): # Update the temporary array with the current # column's values for row in range(rows): temp[row] += mat[row][right] # Find the maximum sum of the subarray for the # current column boundaries sumValue = kadane(temp) # Update the maximum sum found so far maxSum = max(maxSum, sumValue) return maxSum if __name__ == "__main__": mat = [ [1, 2, -1, -4, -20], [-8, -3, 4, 2, 1], [3, 8, 10, 1, 3], [-4, -1, 1, 7, -6] ] res = maxRectSum(mat) print(res) 
C#
using System; class GfG {    // Function to apply Kadane's algorithm to find the  // maximum sum subarray  static int kadane(int[] temp) {  int rows = temp.Length;  int currSum = 0;  int maxSum = int.MinValue;  for (int i = 0; i < rows; i++) {  currSum += temp[i];  // Update maxSum if the current sum is greater  if (maxSum < currSum) {  maxSum = currSum;  }  // If the current sum becomes negative, reset it  // to 0  if (currSum < 0) {  currSum = 0;  }  }  return maxSum;  }  // Function to find the maximum sum of submatrix  static int maxRectSum(int[, ] mat) {  int rows = mat.GetLength(0);  int cols = mat.GetLength(1);  int maxSum = int.MinValue;  // Initialize a temporary array to store row-wise  // sums between left and right boundaries  int[] temp = new int[rows];  // Check for all possible left and right boundaries  for (int left = 0; left < cols; left++) {    // Reset the temporary array for each new left  // boundary  Array.Clear(temp, 0, rows);  for (int right = left; right < cols; right++) {    // Update the temporary array with the  // current column's values  for (int row = 0; row < rows; row++) {  temp[row] += mat[row, right];  }  // Find the maximum sum of the subarray for  // the current column boundaries  int sumValue = kadane(temp);  // Update the maximum sum found so far  maxSum = Math.Max(maxSum, sumValue);  }  }  return maxSum;  }  static void Main() {    int[, ] mat = { { 1, 2, -1, -4, -20 },  { -8, -3, 4, 2, 1 },  { 3, 8, 10, 1, 3 },  { -4, -1, 1, 7, -6 } };  int res = maxRectSum(mat);  Console.WriteLine(res);  } } 
JavaScript
// Function to apply Kadane's algorithm to find the maximum // sum subarray function kadane(temp) {  let rows = temp.length;  let currSum = 0;  let maxSum = -Infinity;  for (let i = 0; i < rows; i++) {  currSum += temp[i];  // Update maxSum if the current sum is greater  if (maxSum < currSum) {  maxSum = currSum;  }  // If the current sum becomes negative, reset it to  // 0  if (currSum < 0) {  currSum = 0;  }  }  return maxSum; } // Function to find the maximum sum of submatrix function maxRectSum(mat) {  const rows = mat.length;  const cols = mat[0].length;  let maxSum = -Infinity;  // Initialize a temporary array to store row-wise sums  // between left and right boundaries  let temp = new Array(rows).fill(0);  // Check for all possible left and right boundaries  for (let left = 0; left < cols; left++) {    // Reset the temporary array for each new left  // boundary  temp.fill(0);  for (let right = left; right < cols; right++) {    // Update the temporary array with the current  // column's values  for (let row = 0; row < rows; row++) {  temp[row] += mat[row][right];  }  // Find the maximum sum of the subarray for the  // current column boundaries  let sumValue = kadane(temp, rows);  // Update the maximum sum found so far  maxSum = Math.max(maxSum, sumValue);  }  }  return maxSum; } // Driver Code const mat = [  [ 1, 2, -1, -4, -20 ],   [ -8, -3, 4, 2, 1 ],  [ 3, 8, 10, 1, 3 ],   [ -4, -1, 1, 7, -6 ] ]; const res = maxRectSum(mat); console.log(res); 

Time complexity: O(n*m2)
Auxiliary Space: O(n)


Explore