Open In App

Largest area rectangular sub-matrix with equal number of 1’s and 0’s

Improve
Improve
Like Article
Like
Save
Share
Report

Given a binary matrix. The problem is to find the largest area rectangular sub-matrix with equal number of 1’s and 0’s. Examples:

Input : mat[][] = { {0, 0, 1, 1},
                    {0, 1, 1, 0},
                    {1, 1, 1, 0},
                    {1, 0, 0, 1} }
Output : 8 sq. units
(Top, left): (0, 0)
(Bottom, right): (3, 1)

Input : mat[][] = { {0, 0, 1, 1},
                    {0, 1, 1, 1} }            
Output : 6 sq. units

The naive solution for this problem is to check every possible rectangle in given 2D array by counting the total number of 1’s and 0’s in that rectangle. This solution requires 4 nested loops and time complexity of this solution would be O(n^4). 

An efficient solution is based on Largest rectangular sub-matrix whose sum is 0 which reduces the time complexity to O(n^3). First of all consider every ‘0’ in the matrix as ‘-1’. Now, the idea is to reduce the problem to 1-D array. We fix the left and right columns one by one and find the largest sub-array with 0 sum contiguous rows for every left and right column pair. We basically find top and bottom row numbers (which have sum zero) for every fixed left and right column pair. To find the top and bottom row numbers, calculate sum 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 find largest subarray with 0 sum in temp[], we can get the index positions of rectangular sub-matrix with sum equal to 0 (i.e. having equal number of 1’s and 0’s). With this process we can find the largest area rectangular sub-matrix with sum equal to 0 (i.e. having equal number of 1’s and 0’s). We can use Hashing technique to find maximum length sub-array with sum equal to 0 in 1-D array in O(n) time. 

Implementation:

CPP




// C++ implementation to find largest area rectangular
// submatrix with equal number of 1's and 0's
#include <bits/stdc++.h>
 
using namespace std;
 
#define MAX_ROW 10
#define MAX_COL 10
 
// This function basically finds largest 0
// sum subarray in arr[0..n-1]. If 0 sum
// doesn't exist, then it returns false. Else
// it returns true and sets starting and
// ending indexes as start and end.
bool subArrWithSumZero(int arr[], int& start, int& end,
                       int n)
{
    // to store cumulative sum
    int sum[n];
 
    // Initialize all elements of sum[] to 0
    memset(sum, 0, sizeof(sum));
 
    // map to store the indexes of sum
    unordered_map<int, int> um;
 
    // build up the cumulative sum[] array
    sum[0] = arr[0];
    for (int i = 1; i < n; i++)
        sum[i] = sum[i - 1] + arr[i];
 
    // to store the maximum length subarray
    // with sum equal to 0
    int maxLen = 0;
 
    // traverse to the sum[] array
    for (int i = 0; i < n; i++) {
        // if true, then there is a subarray
        // with sum equal to 0 from the
        // beginning up to index 'i'
        if (sum[i] == 0) {
            // update the required variables
            start = 0;
            end = i;
            maxLen = (i + 1);
        }
 
        // else if true, then sum[i] has not
        // seen before in 'um'
        else if (um.find(sum[i]) == um.end())
            um[sum[i]] = i;
 
        // sum[i] has been seen before in the
        // unordered_map 'um'
        else {
            // if previous subarray length is smaller
            // than the current subarray length, then
            // update the required variables
            if (maxLen < (i - um[sum[i]])) {
                maxLen = (i - um[sum[i]]);
                start = um[sum[i]] + 1;
                end = i;
            }
        }
    }
 
    // if true, then there is no
    // subarray with sum equal to 0
    if (maxLen == 0)
        return false;
 
    // else return true
    return true;
}
 
// function to find largest area rectangular
// submatrix with equal number of 1's and 0's
void maxAreaRectWithSumZero(int mat[MAX_ROW][MAX_COL],
                            int row, int col)
{
    // to store intermediate values
    int temp[row], startRow, endRow;
 
    // to store the final outputs
    int finalLeft, finalRight, finalTop, finalBottom;
    finalLeft = finalRight = finalTop = finalBottom = -1;
    int maxArea = 0;
 
    // Set the left column
    for (int 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 (int right = left; right < col; right++) {
            // Calculate sum between current left
            // and right for every row 'i'
            // consider value '1' as '1' and
            // value '0' as '-1'
            for (int i = 0; i < row; i++)
                temp[i] += mat[i][right] ? 1 : -1;
 
            // Find largest subarray with 0 sum in
            // temp[]. The subArrWithSumZero() function
            // also sets values of finalTop, finalBottom,
            // finalLeft and finalRight if there exists
            // a subarray with sum 0 in temp
            if (subArrWithSumZero(temp, startRow, endRow,
                                  row)) {
                int area = (right - left + 1)
                           * (endRow - startRow + 1);
 
                // Compare current 'area' with previous area
                // and accordingly update final values
                if (maxArea < area) {
                    finalTop = startRow;
                    finalBottom = endRow;
                    finalLeft = left;
                    finalRight = right;
                    maxArea = area;
                }
            }
        }
    }
 
    // if true then there is no rectangular submatrix
    // with equal number of 1's and 0's
    if (maxArea == 0)
        cout << "No such rectangular submatrix exists:";
 
    // displaying the top left and bottom right boundaries
    // with the area of the rectangular submatrix
    else {
        cout << "(Top, Left): "
             << "(" << finalTop << ", " << finalLeft << ")"
             << endl;
 
        cout << "(Bottom, Right): "
             << "(" << finalBottom << ", " << finalRight
             << ")" << endl;
 
        cout << "Area: " << maxArea << " sq.units";
    }
}
 
// Driver program to test above
int main()
{
    int mat[MAX_ROW][MAX_COL] = { { 0, 0, 1, 1 },
                                  { 0, 1, 1, 0 },
                                  { 1, 1, 1, 0 },
                                  { 1, 0, 0, 1 } };
    int row = 4, col = 4;
    maxAreaRectWithSumZero(mat, row, col);
    return 0;
}


Java




// Java implementation to find largest area rectangular
// submatrix with equal number of 1's and 0's
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // This function basically finds largest 0
    // sum subarray in arr[0..n-1]. If 0 sum
    // doesn't exist, then it returns false. Else
    // it returns true and sets starting and
    // ending indexes as start and end.
    public static boolean
    subArrWithSumZero(int arr[], int start, int end, int n)
    {
        // to store cumulative sum
        int sum[] = new int[n];
 
        // map to store the indexes of sum
        HashMap<Integer, Integer> um
            = new HashMap<Integer, Integer>();
 
        // build up the cumulative sum[] array
        sum[0] = arr[0];
        for (int i = 1; i < n; i++)
            sum[i] = sum[i - 1] + arr[i];
 
        // to store the maximum length subarray
        // with sum equal to 0
        int maxLen = 0;
 
        // traverse to the sum[] array
        for (int i = 0; i < n; i++) {
            // if true, then there is a subarray
            // with sum equal to 0 from the
            // beginning up to index 'i'
            if (sum[i] == 0) {
                // update the required variables
                start = 0;
                end = i;
                maxLen = (i + 1);
            }
 
            // else if true, then sum[i] has not
            // seen before in 'um'
            else if (um.get(sum[i]) == null)
                um.put(sum[i], i);
 
            // sum[i] has been seen before in the
            // unordered_map 'um'
            else {
                // if previous subarray length is smaller
                // than the current subarray length, then
                // update the required variables
                if (maxLen < (i - um.get(sum[i]))) {
                    maxLen = i - um.get(sum[i]);
                    start = i - um.get(sum[i]) + 1;
                    end = i;
                }
            }
        }
 
        // if true, then there is no
        // subarray with sum equal to 0
        if (maxLen == 0)
            return false;
 
        // else return true
        return true;
    }
 
    // function to find largest area rectangular
    // submatrix with equal number of 1's and 0's
    public static void
    maxAreaRectWithSumZero(int mat[][], int row, int col)
    {
        // to store intermediate values
        int temp[] = new int[row];
        int startRow = 0, endRow = 0;
 
        // to store the final outputs
        int finalLeft = -1, finalRight = -1, finalTop = -1,
            finalBottom = -1;
        int maxArea = 0;
 
        // Set the left column
        for (int left = 0; left < col; left++) {
            // Set the right column for the left column
            // set by outer loop
            for (int right = left; right < col; right++) {
                // Calculate sum between current left
                // and right for every row 'i'
                // consider value '1' as '1' and
                // value '0' as '-1'
                for (int i = 0; i < row; i++)
                    temp[i]
                        += (mat[i][right] != 0) ? 1 : -1;
 
                // Find largest subarray with 0 sum in
                // temp[]. The subArrWithSumZero() function
                // also sets values of finalTop,
                // finalBottom, finalLeft and finalRight if
                // there exists a subarray with sum 0 in
                // temp
                if (subArrWithSumZero(temp, startRow,
                                      endRow, row)) {
                    int area = (right - left + 1)
                               * (endRow - startRow + 1);
 
                    // Compare current 'area' with previous
                    // area and accordingly update final
                    // values
                    if (maxArea < area) {
                        finalTop = startRow;
                        finalBottom = endRow;
                        finalLeft = left;
                        finalRight = right;
                        maxArea = area;
                    }
                }
            }
        }
 
        // if true then there is no rectangular submatrix
        // with equal number of 1's and 0's
        if (maxArea == 0)
            System.out.print(
                "No such rectangular submatrix exists:");
 
        // displaying the top left and bottom right
        // boundaries with the area of the rectangular
        // submatrix
        else {
            System.out.println("(Top, Left): "
                               + "(" + finalTop + ", "
                               + finalLeft + ")");
 
            System.out.println("(Bottom, Right): "
                               + "(" + finalBottom + ", "
                               + finalRight + ")");
 
            System.out.println("Area: " + maxArea
                               + " sq.units");
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int mat[][] = { { 0, 0, 1, 1 },
                        { 0, 1, 1, 0 },
                        { 1, 1, 1, 0 },
                        { 1, 0, 0, 1 } };
        int row = 4, col = 4;
        maxAreaRectWithSumZero(mat, row, col);
    }
}
 
// This code is contributed by Rohit Pradhan


Python3




# code
 
# this function first convert 0->-1. Then it creates an memory array
# which stores sum of all element in row from column index i to j
# then each array is passed into getmax function
def solve(m,R,C):
    for i in range(R):
        for j in range(C):
            if m[i][j] == 0:
                m[i][j] = -1
                 
    maxval =0
    temparr = [[0]*(C+1) for _ in range(R)]
    for i in range(C):
        for j in range(i, C):
            temp = []
            for k in range(R):
                 
                if i==0:
                    temparr[k][j+1] = temparr[k][j]+m[k][j]
                    temp.append(temparr[k][j+1])
                else:
                    temp.append(temparr[k][j+1]-m[k][i])
             
            maxval = max(maxval, getmax(temp)*(j-i+1))
             
     
    return maxval
     
 
# This function basically finds largest 0
# sum subarray in arr[0..n-1]. it returns
# length of largest subarray in arr with sum of subarray is zero.
def getmax(arr):
     
    dic = dict()
    currsum  = 0
    maxlen = 0
    for i in range(len(arr)):
        currsum+= arr[i]
         
        if currsum ==0:
            maxlen = i+1
             
         
        if currsum not in dic:
            dic[currsum] = i
             
        else:
            temp = i- dic[currsum]
             
            maxlen = max(temp, maxlen)
             
     
    return maxlen
 
 
 
if __name__ == '__main__':
    # m = [[0, 0, 1, 1],[0, 1, 1, 0],[1, 1, 1, 0],[1, 0, 0, 1]]
    m = [[0, 0, 1, 1],
                    [0, 1, 1, 1]]  
     
    R = len(m)
    C = len(m[0])
     
    ans = solve(m, R, C)
    print(ans)


C#




// C# implementation to find largest area rectangular
// submatrix with equal number of 1's and 0's
using System;
using System.Collections.Generic;
 
public class GFG {
 
    // This function basically finds largest 0
    // sum subarray in arr[0..n-1]. If 0 sum
    // doesn't exist, then it returns false. Else
    // it returns true and sets starting and
    // ending indexes as start and end.
    public static bool
    subArrWithSumZero(int[] arr, int start, int end, int n)
    {
        // to store cumulative sum
        int[] sum = new int[n];
 
        // map to store the indexes of sum
        Dictionary<int, int> um
            = new Dictionary<int, int>();
 
        // build up the cumulative sum[] array
        sum[0] = arr[0];
        for (int i = 1; i < n; i++)
            sum[i] = sum[i - 1] + arr[i];
 
        // to store the maximum length subarray
        // with sum equal to 0
        int maxLen = 0;
 
        // traverse to the sum[] array
        for (int i = 0; i < n; i++) {
            // if true, then there is a subarray
            // with sum equal to 0 from the
            // beginning up to index 'i'
            if (sum[i] == 0) {
                // update the required variables
                start = 0;
                end = i;
                maxLen = (i + 1);
            }
 
            // else if true, then sum[i] has not
            // seen before in 'um'
            else if (!um.ContainsKey(sum[i]))
                um[sum[i]] = i;
 
            // sum[i] has been seen before in the
            // unordered_map 'um'
            else {
                // if previous subarray length is smaller
                // than the current subarray length, then
                // update the required variables
                if (maxLen < (i - um[sum[i]])) {
                    maxLen = i - um[sum[i]];
                    start = i - um[sum[i]] + 1;
                    end = i;
                }
            }
        }
 
        // if true, then there is no
        // subarray with sum equal to 0
        if (maxLen == 0)
            return false;
 
        // else return true
        return true;
    }
 
    // function to find largest area rectangular
    // submatrix with equal number of 1's and 0's
    public static void
    maxAreaRectWithSumZero(int[, ] mat, int row, int col)
    {
        // to store intermediate values
        int[] temp = new int[row];
        int startRow = 0, endRow = 0;
 
        // to store the final outputs
        int finalLeft = -1, finalRight = -1, finalTop = -1,
            finalBottom = -1;
        int maxArea = 0;
 
        // Set the left column
        for (int left = 0; left < col; left++) {
            // Set the right column for the left column
            // set by outer loop
            for (int right = left; right < col; right++) {
                // Calculate sum between current left
                // and right for every row 'i'
                // consider value '1' as '1' and
                // value '0' as '-1'
                for (int i = 0; i < row; i++)
                    temp[i]
                        += (mat[i, right] != 0) ? 1 : -1;
 
                // Find largest subarray with 0 sum in
                // temp[]. The subArrWithSumZero() function
                // also sets values of finalTop,
                // finalBottom, finalLeft and finalRight if
                // there exists a subarray with sum 0 in
                // temp
                if (subArrWithSumZero(temp, startRow,
                                      endRow, row)) {
                    int area = (right - left + 1)
                               * (endRow - startRow + 1);
 
                    // Compare current 'area' with previous
                    // area and accordingly update final
                    // values
                    if (maxArea < area) {
                        finalTop = startRow;
                        finalBottom = endRow;
                        finalLeft = left;
                        finalRight = right;
                        maxArea = area;
                    }
                }
            }
        }
 
        // if true then there is no rectangular submatrix
        // with equal number of 1's and 0's
        if (maxArea == 0)
            Console.Write(
                "No such rectangular submatrix exists:");
 
        // displaying the top left and bottom right
        // boundaries with the area of the rectangular
        // submatrix
        else {
            Console.WriteLine("(Top, Left): "
                              + "(" + finalTop + ", "
                              + finalLeft + ")");
 
            Console.WriteLine("(Bottom, Right): "
                              + "(" + finalBottom + ", "
                              + finalRight + ")");
 
            Console.WriteLine("Area: " + maxArea
                              + " sq.units");
        }
    }
 
    static public void Main()
    {
 
        // Code
        int[, ] mat = { { 0, 0, 1, 1 },
                        { 0, 1, 1, 0 },
                        { 1, 1, 1, 0 },
                        { 1, 0, 0, 1 } };
        int row = 4, col = 4;
        maxAreaRectWithSumZero(mat, row, col);
    }
}
 
// This code is contributed by lokesh


Javascript




// JavaScript implementation to find largest area
// rectangular submatrix with equal number of 1's and 0's
 
// This function basically finds largest 0
// sum subarray in arr[0..n-1]. If 0 sum
// doesn't exist, then it returns false. Else
// it returns true and sets starting and
// ending indexes as start and end.
function subArrWithSumZero(arr, start, end, n)
{
 
    // to store cumulative sum
    var sum = new Array(n);
     
    // map to store the indexes of sum
    var um = new Map();
     
    // build up the cumulative sum[] array
    sum[0] = arr[0];
    for (let i = 1; i < n; i++)
        sum[i] = sum[i - 1] + arr[i];
 
    // to store the maximum length subarray
    // with sum equal to 0
    var maxLen = 0;
     
    for(let i=0;i<n;i++)
    {
     
        // if true, then there is a subarray
        // with sum equal to 0 from the
        // beginning up to index 'i'
        if (sum[i] == 0)
        {
         
            // update the required variables
            start = 0;
            end = i;
            maxLen = (i + 1);
        }
         
        // else if true, then sum[i] has not
        // seen before in 'um'
        else if(um.get(sum[i])==null){
            um.set(sum[i], i);
        }
         
        // sum[i] has been seen before in the
        // unordered_map 'um'
        else
        {
         
            // if previous subarray length is smaller
            // than the current subarray length, then
            // update the required variables
            if (maxLen < (i - um.get(sum[i]))) {
                maxLen = i - um.get(sum[i]);
                start = i - um.get(sum[i]) + 1;
                end = i;
            }
        }
    }
     
    // if true, then there is no
    // subarray with sum equal to 0
    if (maxLen == 0)
        return false;
 
    // else return true
    return true;
}
 
// function to find largest area rectangular
// submatrix with equal number of 1's and 0's
function maxAreaRectWithSumZero(mat, row, col)
{
 
    // to store intermediate values
    var temp = new Array(row);
    var startRow = 0, endRow = 0;
     
    // to store the final outputs
    var finalLeft = -1, finalRight = -1, finalTop = -1, finalBottom = -1;
    var maxArea = 0;
     
    // Set the left column
    for(let left = 0; left < col; left++)
    {
     
        // Set the right column for the left column
        // set by outer loop
        for(let right = left; right < col; right++)
        {
         
            // Calculate sum between current left
            // and right for every row 'i'
            // consider value '1' as '1' and
            // value '0' as '-1'
            for(let i = 0;i < row; i++){
                temp[i] += (mat[i][right] != 0) ? 1 : -1;
            }
             
            // Find largest subarray with 0 sum in
            // temp[]. The subArrWithSumZero() function
            // also sets values of finalTop,
            // finalBottom, finalLeft and finalRight if
            // there exists a subarray with sum 0 in
            // temp
            if(subArrWithSumZero(temp, startRow, endRow, row)){
                let area = (right - left + 1) * (endRow - startRow + 1);
                 
                // Compare current 'area' with previous
                // area and accordingly update final
                // values
                if (maxArea < area) {
                    finalTop = startRow;
                    finalBottom = endRow;
                    finalLeft = left;
                    finalRight = right;
                    maxArea = area;
                }
            }
        }
    }
     
    // if true then there is no rectangular submatrix
    // with equal number of 1's and 0's
    if (maxArea == 0){
        console.log("No such rectangular submatrix exists:");
    }
     
    // displaying the top left and bottom right
    // boundaries with the area of the rectangular
    // submatrix
    else{
        console.log("(Top, Left): "
                           + "(" + finalTop + ", "
                           + finalLeft + ")" + "<br>");
 
        console.log("(Bottom, Right): "
                           + "(" + finalBottom + ", "
                           + finalRight + ")" + "<br>");
 
        console.log("Area: " + maxArea
                           + " sq.units" + "<br>");
    }
}
 
var mat = [ [ 0, 0, 1, 1 ],
            [ 0, 1, 1, 0 ],
            [ 1, 1, 1, 0 ],
            [ 1, 0, 0, 1 ] ]
         
var row = 4, col = 4;
maxAreaRectWithSumZero(mat, row, col);
 
// This code is contributed by lokeshmvs21.


Output

(Top, Left): (0, 0)
(Bottom, Right): (3, 1)
Area: 8 sq.units

Time Complexity: O(n3) Auxiliary Space: O(n)



Last Updated : 13 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads