Open In App

Largest Submatrix With Sum 0

Last Updated : 13 Jan, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a 2D matrix of dimension n x m, the task is to find the area of largest submatrix whose sum is 0.

Examples: 

Input: mat[][] = [[9, 7, 16, 5], [1, -6, -7, 3], [1, 8, 7, 9], [7, -2, 0, 10]]
Output: 6
Explanation:

Largest-SubMatrix-with-Sum-0


Input: mat[][] = [[1, 2, 3], [-3, -2, -1], [1, 7, 5]]
Output: 6
Explanation:

Largest-SubMatrix-with-Sum-0-2


Input: mat[][] = [[1, -1], [-1, 1]]
Output: 4
Explanation: The largest submatrix with sum 0 is [[1, -1], [-1, 1]].

[Naive Approach] Using four Nested Loops - O(n^4) Time and O(n^2) Space

The naive solution for this problem is to check the sum of every possible rectangle in given 2D array. For this we can use four nested loop to fix the upper row, bottom row, left column and right column of the sub matrix.
Now for each such sub matrix we can find its sum using a 2D prefix sum matrix in constant time. If this calculated sum is equal to 0 then update the maximum area found.

[Expected Approach] Using Prefix Sum - O(n^3) Time and O(n) Space

The idea is to iterate over all pairs of rows to fix the top and bottom row (or height) of the 0-sum submatrix. Let's see how to get the width of the largest submatrix with 0-sum.

To find the width of largest submatrix with zero sum for a given top and bottom row pair:

  • For a given top-bottom pair, we compute the column-wise cumulative sum in a temporary array temp[].
  • Now find the length of Longest Subarray with 0 Sum in temp[] array.

The Length of longest Subarray with 0 Sum in temp[] array will also be the width of the largest 0-sum submatrix.

C++
// C++ program to find Largest rectangular
// sub-matrix whose sum is 0
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

int maxZeroSumSubarray(vector<int> &arr) {
    int prefSum = 0;
  	int maxLength = 0;

    // Hash map to store the first index of each prefix sum
    unordered_map<int, int> mp;

    // Iterate through the array to find subarrays with zero sum
    for (int i = 0; i < arr.size(); i++) {
        prefSum += arr[i];
      
      	if (prefSum == 0) 
          	maxLength = i+1;

        if (mp.find(prefSum) != mp.end()) {
            // If this prefSum repeats, find subarray length.
            maxLength = max(maxLength, (i - mp[prefSum]));
        }
        else {
            // Only store the index of the first occurrence of prefSum
            mp[prefSum] = i;
        }
    }

    return maxLength;
}

int zeroSumSubmat(vector<vector<int>> &mat) {
    int rows = mat.size();
    int cols = mat[0].size();
    int maxArea = 0;

    for (int i = 0; i < rows; i++) {
      
        // Temporary array to store the column-wise cumulative sum
        vector<int> temp(cols, 0);

        // Iterate over each row from i to j
        for (int j = i; j < rows; j++) {
          
            // Accumulate the column-wise sum for rows between i and j
            for (int k = 0; k < cols; k++)
                temp[k] += mat[j][k];

            // Find the longest zero-sum subarray in column sums
            int len = maxZeroSumSubarray(temp);

			// Update the maximum area 
            maxArea = max(maxArea, (j - i + 1) * len);
        }
    }

    return maxArea;
}

int main() {
    vector<vector<int>> mat = {{9, 7, 16, 5}, 
                               {1, -6, -7, 3}, 
                               {1, 8, 7, 9}, 
                               {7, -2, 0, 10}
                              };
    cout << zeroSumSubmat(mat) << endl;
    return 0;
}
Java
// Java program to find Largest rectangular
// sub-matrix whose sum is 0

import java.util.HashMap;
class GfG {
  
    // Function to find the largest zero-sum subarray
    static int maxZeroSumSubarray(int[] arr) {
        int prefSum = 0;
        int maxLength = 0;

        // Hash map to store the first index of each prefix sum
        HashMap<Integer, Integer> mp = new HashMap<>();

        // Iterate through the array to find subarrays with zero sum
        for (int i = 0; i < arr.length; i++) {
            prefSum += arr[i];

            if (prefSum == 0) 
                maxLength = i + 1;

            if (mp.containsKey(prefSum)) {
                // If this prefSum repeats, find subarray length.
                maxLength = Math.max(maxLength, (i - mp.get(prefSum)));
            } else {
                // Only store the index of the first occurrence of prefSum
                mp.put(prefSum, i);
            }
        }

        return maxLength;
    }

    static int zeroSumSubmat(int[][] mat) {
        int rows = mat.length;
        int cols = mat[0].length;
        int maxArea = 0;

        for (int i = 0; i < rows; i++) {

            // Temporary array to store the column-wise cumulative sum
            int[] temp = new int[cols];

            // Iterate over each row from i to j
            for (int j = i; j < rows; j++) {

                // Accumulate the column-wise sum for rows between i and j
                for (int k = 0; k < cols; k++)
                    temp[k] += mat[j][k];

                // Find the longest zero-sum subarray in column sums
                int len = maxZeroSumSubarray(temp);

                // Update the maximum area 
                maxArea = Math.max(maxArea, (j - i + 1) * len);
            }
        }

        return maxArea;
    }

    public static void main(String[] args) {
        int[][] mat = {
            {9, 7, 16, 5}, 
            {1, -6, -7, 3}, 
            {1, 8, 7, 9}, 
            {7, -2, 0, 10}
        };
        System.out.println(zeroSumSubmat(mat));
    }
}
Python
# Python program to find Largest rectangular
# sub-matrix whose sum is 0

def maxZeroSumSubarray(arr):
    prefSum = 0
    maxLength = 0

    # Hash map to store the first index of each prefix sum
    mp = {}

    # Iterate through the array to find subarrays with zero sum
    for i in range(len(arr)):
        prefSum += arr[i]

        if prefSum == 0:
            maxLength = i + 1

        if prefSum in mp:
            # If this prefSum repeats, find subarray length.
            maxLength = max(maxLength, i - mp[prefSum])
        else:
            # Only store the index of the first occurrence of prefSum
            mp[prefSum] = i

    return maxLength

def zeroSumSubmat(mat):
    rows = len(mat)
    cols = len(mat[0])
    maxArea = 0

    for i in range(rows):

        # Temporary array to store the column-wise cumulative sum
        temp = [0] * cols

        # Iterate over each row from i to j
        for j in range(i, rows):

            # Accumulate the column-wise sum for rows between i and j
            for k in range(cols):
                temp[k] += mat[j][k]

            # Find the longest zero-sum subarray in column sums
            lenSubarray = maxZeroSumSubarray(temp)

            # Update the maximum area 
            maxArea = max(maxArea, (j - i + 1) * lenSubarray)

    return maxArea

if __name__ == '__main__':
    mat = [
        [9, 7, 16, 5], 
        [1, -6, -7, 3], 
        [1, 8, 7, 9], 
        [7, -2, 0, 10]
    ]
    print(zeroSumSubmat(mat))
C#
// C# program to find Largest rectangular
// sub-matrix whose sum is 0

using System;
using System.Collections.Generic;

class GfG {
  
    // Function to find the largest zero-sum subarray
    static int maxZeroSumSubarray(int[] arr) {
        int prefSum = 0;
        int maxLength = 0;

        // Hash map to store the first index of each prefix sum
        Dictionary<int, int> mp = new Dictionary<int, int>();

        // Iterate through the array to find subarrays with zero sum
        for (int i = 0; i < arr.Length; i++) {
            prefSum += arr[i];

            if (prefSum == 0)
                maxLength = i + 1;

            if (mp.ContainsKey(prefSum)) {
                // If this prefSum repeats, find subarray length.
                maxLength = Math.Max(maxLength, i - mp[prefSum]);
            } else {
                // Only store the index of the first occurrence of prefSum
                mp[prefSum] = i;
            }
        }

        return maxLength;
    }

    static int zeroSumSubmat(int[][] mat) {
        int rows = mat.Length;
        int cols = mat[0].Length;
        int maxArea = 0;

        for (int i = 0; i < rows; i++) {

            // Temporary array to store the column-wise cumulative sum
            int[] temp = new int[cols];

            // Iterate over each row from i to j
            for (int j = i; j < rows; j++) {

                // Accumulate the column-wise sum for rows between i and j
                for (int k = 0; k < cols; k++)
                    temp[k] += mat[j][k];

                // Find the longest zero-sum subarray in column sums
                int len = maxZeroSumSubarray(temp);

                // Update the maximum area 
                maxArea = Math.Max(maxArea, (j - i + 1) * len);
            }
        }

        return maxArea;
    }

    static void Main() {
        int[][] mat = {
            new int[] {9, 7, 16, 5}, 
            new int[] {1, -6, -7, 3}, 
            new int[] {1, 8, 7, 9}, 
            new int[] {7, -2, 0, 10}
        };
        Console.WriteLine(zeroSumSubmat(mat));
    }
}
JavaScript
// JavaScript program to find Largest rectangular
// sub-matrix whose sum is 0

function maxZeroSumSubarray(arr) {
    let prefSum = 0;
    let maxLength = 0;

    // Hash map to store the first index of each prefix sum
    const mp = new Map();

    // Iterate through the array to find subarrays with zero sum
    for (let i = 0; i < arr.length; i++) {
        prefSum += arr[i];

        if (prefSum === 0)
            maxLength = i + 1;

        if (mp.has(prefSum)) {
        
            // If this prefSum repeats, find subarray length
            maxLength = Math.max(maxLength, i - mp.get(prefSum));
        } else {
        
            // Only store the index of the first occurrence of prefSum
            mp.set(prefSum, i);
        }
    }

    return maxLength;
}

function zeroSumSubmat(mat) {
    const rows = mat.length;
    const cols = mat[0].length;
    let maxArea = 0;

    for (let i = 0; i < rows; i++) {

        // Temporary array to store the column-wise cumulative sum
        const temp = Array(cols).fill(0);

        // Iterate over each row from i to j
        for (let j = i; j < rows; j++) {

            // Accumulate the column-wise sum for rows between i and j
            for (let k = 0; k < cols; k++)
                temp[k] += mat[j][k];

            // Find the longest zero-sum subarray in column sums
            const len = maxZeroSumSubarray(temp);

            // Update the maximum area 
            maxArea = Math.max(maxArea, (j - i + 1) * len);
        }
    }

    return maxArea;
}

// Driver Code
const mat = [
    [9, 7, 16, 5], 
    [1, -6, -7, 3], 
    [1, 8, 7, 9], 
    [7, -2, 0, 10]
];
console.log(zeroSumSubmat(mat));

Output
6

Next Article
Article Tags :
Practice Tags :

Similar Reads