Open In App

Maximum size rectangle binary sub-matrix with all 1s | Set 2

Improve
Improve
Like Article
Like
Save
Share
Report

Given a binary matrix mat[][] of size N*M, find the maximum size rectangle binary-sub-matrix with all 1’s. 

Examples:

Input: mat[][] = { {0, 1, 1, 0}, 
                                {1, 1, 1, 1}, 
                               {1, 1, 1, 1}, 
                              {1, 1, 0, 0} }
Output: 8
Explanation: The largest rectangle formed with only 1s is either: (0, 1) to (2, 2) or (1, 1) to (2, 3)  which is
1 1 1 1
1 1 1 1

Input: mat[][] = { {0, 1, 1}, 
                                {1, 1, 1}, 
                               {0, 1, 1} }
Output: 6
Explanation: The largest rectangle with only 1’s is from (0, 1) to (2, 2) which is
1 1
1 1
1 1

 

Approach: This approach uses the concept of Largest Rectangular Area in Histogram. But the approach to get the maximum area for each row will be different than Set-1

  • Consider each row as the base of the histogram chart formed with all 1s.
  • For each row, increase height of a bar by the amount of the previous row, only if the value in current row is 1 and calculate the largest rectangular area of that histogram.
  • The largest rectangular area of a histogram among all possible base rows is the required are of the rectangle.

Illustration:

Consider the matrix:
mat[][] = 0 1 1 0
                  1 1 1 1
                  1 1 1 1
                  1 1 0 0 

Calculate maxarea for the first row mat[0]
        => height row[0] = 0 1 1 0. 
        => area  = height* breadth = 1 * 2 = 2

Calculate maxarea for the first row mat[1]
        => update height of mat[1] with mat[0] i.e., mat[1][i] = mat[0][i] + 1 if mat[1][i] = 1, else 0
        => height row[1] = 1 2 2 1. 
        => area  = height* breadth = 2 * 2 = 4

Calculate maxarea for the first row mat[2]
        => update height of mat[2] with mat[1]. i.e., mat[2][i] = mat[1][i] + 1 if mat[2][i] = 1, else 0.
        => height row[2] = 2 3 3 2. 
        => area  = height* breadth = 2 * 4 = 8 (nextsmaller index of mat[2][0] = 4, and previous smaller index = 0. area = 2*(4 – 0))

Calculate maxarea for the first row mat[3]
        => update height of mat[3] with mat[2]. i.e., mat[3][i] = mat[2][i] + 1 if mat[3][i] = 1, else 0.
        => height row[3] = 3 4 0 0. 
        => area  = height* breadth = 3 * 2 = 6 (nextsmaller index of mat[3][0] = 2, and previous smaller index = 0. area = 3*(2 – 0))
        => here 3 4 0 0 is due to the reason that when mat[i][j] = 0 then don’t add previous heights into it. 

Thus maxarea = max of(2, 4, 8, 6) = 8.

This approach can be broken into two parts: 

  • Calculate heights of histogram for each row as base. 
    • Run a loop to traverse through the rows.
    • Now If the current row is not the first row then update the height for that cell as follows,  
      • If mat[i][j] is not zero then matrix[i][j] = matrix[i-1][j] + matrix[i][j]
      • Else mat[i][j] = 0.
  • Calculate largest rectangular area in histogram of 1s for each row as base.
    • First calculate the heights for each row as base as mentioned above.
    • Create two arrays nextSmallereElemen[] and previouSmallerElement[] to store the indices of previous smaller elements and next smaller elements respectively. Refer to this article to find the previous and next smaller element.
    • Now for every element, calculate area by taking this jth element as the smallest in the range nextSmallereElemen[j]  and previouSmallerElement[j] and multiplying it with the difference of nextSmallereElemen[j]  and previouSmallerElement[j]
      • So, height will be the jth element in the given input array. And breadth will be, breadth = nextSmallereElemen[j] – previouSmallerElement[j].
    • Finally, find the maximum of all the areas to get the desired maximum area.
  • Find the maximum areas among all the rows, and that will be the required area of the rectangle.

Below is the implementation for the above approach:

C++




// C++ code for the above approach:
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find next smaller element
vector<int> nextsmallerelement(vector<int>& arr,
                               int n)
{
 
    stack<int> st;
 
    // For the elements which dont have
    // next smaller element ans will be -1
    st.push(-1);
 
    // Store indices in output
    vector<int> right(n);
 
    // Start from last index
    for (int i = n - 1; i >= 0; i--) {
 
        // If top element is sorted then
        // no need to do anything, just store
        // the answer and push the
        // current element in stack
        if ((st.top() != -1)
            && arr[st.top()] < arr[i]) {
            right[i] = st.top();
            st.push(i);
        }
        else {
            while ((st.top() != -1)
                   && arr[st.top()]
                          >= arr[i]) {
                st.pop();
            }
            right[i] = st.top();
            st.push(i);
        }
    }
    return right;
}
 
// Function to find previous smaller element
vector<int> previousmallerelement(vector<int>& arr,
                                  int n)
{
    stack<int> st;
    st.push(-1);
    vector<int> left(n);
 
    // Start from first index
    for (int i = 0; i < n; i++) {
        if ((st.top() != -1)
            && arr[st.top()] < arr[i]) {
            left[i] = st.top();
            st.push(i);
        }
        else {
            while ((st.top() != -1)
                   && arr[st.top()]
                          >= arr[i]) {
                st.pop();
            }
            left[i] = st.top();
            st.push(i);
        }
    }
    return left;
}
 
// Function to get the maximum area
// considering each row as the histogram base
int getMaxArea(vector<int>& arr, int n)
{
    vector<int> right(n);
    right = nextsmallerelement(arr, n);
 
    // Find the smallest element than
    // curr element in right side
 
    vector<int> left(n);
    left = previousmallerelement(arr, n);
 
    // Find the smallest element
    // than curr element in left side
    int maxarea = INT_MIN;
 
    // Now the left and right vector have
    // index of smallest element in left and
    // right respectively, thus the difference
    // of right - left - 1 will give us
    // breadth and thus
    // area = height(curr==arr[i]) * breadth;
    for (int i = 0; i < n; i++) {
        int height = arr[i];
        if (right[i] == -1) {
            right[i] = n;
        }
        int breadth = right[i] - left[i] - 1;
        maxarea = max(maxarea,
                      height * breadth);
    }
    return maxarea;
}
 
// Function to calculate
// the maximum area of rectangle
int maxRectangleArea(vector<vector<int> >& M,
                     int n, int m)
{
 
    // Calculate maxarea for first row
    int area = getMaxArea(M[0], m);
    int maxarea = area;
 
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (M[i][j] != 0) {
 
                // Add heights of previous rows
                // into current
                M[i][j] = M[i][j]
                          + M[i - 1][j];
            }
            else {
 
                // If current height is 0 then
                // don't add previous heights
                M[i][j] = 0;
            }
        }
        maxarea = max(maxarea,
                      getMaxArea(M[i], m));
    }
    return maxarea;
}
 
// Driver code
int main()
{
    int N = 4, M = 4;
    vector<vector<int> > amt = {
        { 0, 1, 1, 0 },
        { 1, 1, 1, 1 },
        { 1, 1, 1, 1 },
        { 1, 1, 0, 0 },
    };
 
    cout << maxRectangleArea(amt, N, M);
    return 0;
}


Java




/*package whatever //do not write package name here */
import java.util.*;
class GFG{
 
  public static int[] nextsmallerelement(int[] arr, int n)
  {
 
    Stack<Integer> st = new Stack<>();
 
    // For the elements which dont have
    // next smaller element ans will be -1
    st.push(-1);
 
    // Store indices in output
    int[] right  = new int[n];
 
    // Start from last index
    for (int i = n - 1; i >= 0; i--) {
 
      // If top element is sorted then
      // no need to do anything, just store
      // the answer and push the
      // current element in stack
      if ((st.peek() != -1)
          && arr[st.peek()] < arr[i]) {
        right[i] = st.peek();
        st.push(i);
      }
      else {
        while ((st.peek() != -1)
               && arr[st.peek()]
               >= arr[i]) {
          st.pop();
        }
        right[i] = st.peek();
        st.push(i);
      }
    }
    return right;
  }
 
  public static int[] previousmallerelement(int arr[],int n)
  {
    Stack<Integer> st = new Stack<>();
    st.push(-1);
 
    int[] left  = new int[n];
 
    // Start from first index - Difference Between Next and Previous Smaller element
    for (int i = 0; i < n; i++) {
      if ((st.peek() != -1)
          && arr[st.peek()] < arr[i]) {
        left[i] = st.peek();
        st.push(i);
      }
      else {
        while ((st.peek() != -1)
               && arr[st.peek()]
               >= arr[i]) {
          st.pop();
        }
        left[i] = st.peek();
        st.push(i);
      }
    }
    return left;
  }
 
  public static int getMaxArea(int [] arr, int n)
  {
    int [] right = new int [n];
    right = nextsmallerelement(arr, n);
 
    // Find the smallest element than
    // curr element in right side
 
    int [] left = new int [n];
    left = previousmallerelement(arr, n);
 
    // Find the smallest element
    // than curr element in left side
    int maxarea = Integer.MIN_VALUE;
 
    // Now the left and right array have
    // index of smallest element in left and
    // right respectively, thus the difference
    // of right - left - 1 will give us
    // breadth and thus
    // area = height(curr==arr[i]) * breadth;
    for (int i = 0; i < n; i++) {
      int height = arr[i];
      if (right[i] == -1) {
        right[i] = n;
      }
      int breadth = right[i] - left[i] - 1;
      maxarea = Math.max(maxarea,
                         height * breadth);
    }
    return maxarea;
  }
 
  public static int maxRectangleArea(int [][] M, int R, int C)
  {
    int area = getMaxArea(M[0], R);
    int maxarea = area;
 
    for (int i = 1; i < R; i++) {
      for (int j = 0; j < C; j++) {
        if (M[i][j] != 0) {
 
          // Add heights of previous rows
          // into current
          M[i][j] = M[i][j]
            + M[i - 1][j];
        }
        else {
 
          // If current height is 0 then
          // don't add previous heights
          M[i][j] = 0;
        }
      }
      maxarea = Math.max(maxarea,
                         getMaxArea(M[i], R));
    }
    return maxarea;
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // Given array
    int R = 4, C = 4;
    int [][]amt = {
      { 0, 1, 1, 0 },
      { 1, 1, 1, 1 },
      { 1, 1, 1, 1 },
      { 1, 1, 0, 0 },
    };
    System.out.println(maxRectangleArea(amt, R, C));
  }
}
 
// This code is contributed by rupeshsk30.


Python3




# Python code for the above approach:
 
INT_MIN = -2147483647 - 1
 
# Function to find next smaller element
def nextsmallerelement(arr, n):
 
    st = []
 
    # For the elements which dont have
    # next smaller element ans will be -1
    st.append(-1)
 
    # Store indices in output
    right = [0 for i in range(n)]
 
    # Start from last index
    for i in range(n-1,-1,-1):
 
# If top element is sorted then
# no need to do anything, just store
# the answer and append the
# current element in stack
        if ((st[- 1] != -1) and arr[st[- 1]] < arr[i]):
            right[i] = st[- 1]
            st.append(i)
        else:
            while ((st[- 1] != -1) and arr[st[- 1]] >= arr[i]):
                st.pop()
     
            right[i] = st[- 1]
            st.append(i)
    return right
 
# Function to find previous smaller element
def previousmallerelement(arr, n):
    st = []
    st.append(-1)
    left = [0 for i in range(n)]
 
    # Start from first index
    for i in range(n):
        if((st[- 1] != -1) and arr[st[- 1]] < arr[i]):
            left[i] = st[- 1]
            st.append(i)
        else:
            while ((st[- 1] != -1) and arr[st[- 1]]>= arr[i]):
                st.pop()
             
            left[i] = st[- 1]
            st.append(i)
 
    return left
 
# Function to get the maximum area
# considering each row as the histogram base
def getMaxArea(arr, n):
    right = [0 for i in range(n)]
    right = nextsmallerelement(arr, n)
 
    # Find the smallest element than
    # curr element in right side
 
    left = [0 for i in range(n)]
    left = previousmallerelement(arr, n)
 
    # Find the smallest element
    # than curr element in left side
    maxarea = INT_MIN
 
    # Now the left and right vector have
    # index of smallest element in left and
    # right respectively, thus the difference
    # of right - left - 1 will give us
    # breadth and thus
    # area = height(curr==arr[i]) * breadth
    for i in range(n):
        height = arr[i]
        if (right[i] == -1):
            right[i] = n
 
        breadth = right[i] - left[i] - 1
        maxarea = max(maxarea,height * breadth)
     
    return maxarea
 
# Function to calculate
# the maximum area of rectangle
def maxRectangleArea(M, n, m):
 
    # Calculate maxarea for first row
    area = getMaxArea(M[0], m)
    maxarea = area
 
    for i in range(1,n):
        for j in range(m):
            if (M[i][j] != 0):
 
                # Add heights of previous rows into current
                M[i][j] = M[i][j] + M[i - 1][j]
 
            else:
 
                # If current height is 0 then
                # don't add previous heights
                M[i][j] = 0
 
        maxarea = max(maxarea,getMaxArea(M[i], m))
    return maxarea
 
# Driver code
 
N,M = 4,4
amt = [ [0, 1, 1, 0],[1, 1, 1, 1],[1, 1, 1, 1],[1, 1, 0, 0]]
 
print(maxRectangleArea(amt, N, M))
 
# This code is contributed by shinjanpatra


C#




// C# code for the above approach:
using System;
using System.Collections;
using System.Collections.Generic;
 
public class GFG {
 
  public static int[] NextSmallerElement(int[, ] M, int R,
                                         int rowIndex)
  {
    Stack<int> st = new Stack<int>();
 
    // For the elements which dont have
    // next smaller element ans will be -1
    st.Push(-1);
 
    // Store indices in output
    int[] right = new int[R];
 
    // Start from last index
    for (int i = R - 1; i >= 0; i--) {
      // If top element is sorted then
      // no need to do anything, just store
      // the answer and push the
      // current element in stack
      if ((st.Peek() != -1)
          && M[rowIndex, st.Peek()]
          < M[rowIndex, i]) {
        right[i] = st.Peek();
        st.Push(i);
      }
      else {
        while ((st.Peek() != -1)
               && M[rowIndex, st.Peek()]
               >= M[rowIndex, i]) {
          st.Pop();
        }
        right[i] = st.Peek();
        st.Push(i);
      }
    }
    return right;
  }
 
  public static int[] PreviousSmallerElement(int[, ] M,
                                             int R,
                                             int rowIndex)
  {
    Stack<int> st = new Stack<int>();
    st.Push(-1);
 
    int[] left = new int[R];
 
    // Start from first index - Difference Between Next
    // and Previous Smaller element
    for (int i = 0; i < R; i++) {
      if ((st.Peek() != -1)
          && M[rowIndex, st.Peek()]
          < M[rowIndex, i]) {
        left[i] = st.Peek();
        st.Push(i);
      }
      else {
        while ((st.Peek() != -1)
               && M[rowIndex, st.Peek()]
               >= M[rowIndex, i]) {
          st.Pop();
        }
        left[i] = st.Peek();
        st.Push(i);
      }
    }
    return left;
  }
 
  public static int GetMaxArea(int[, ] M, int R,
                               int rowIndex)
  {
    int[] right = NextSmallerElement(M, R, rowIndex);
 
    // Find the smallest element than
    // curr element in right side
 
    int[] left = PreviousSmallerElement(M, R, rowIndex);
 
    // Find the smallest element
    // than curr element in left side
    int maxarea = int.MinValue;
 
    // Now the left and right array have
    // index of smallest element in left and
    // right respectively, thus the difference
    // of right - left - 1 will give us
    // breadth and thus
    // area = height(curr==arr[i]) * breadth;
    for (int i = 0; i < R; i++) {
      int height = M[rowIndex, i];
      if (right[i] == -1) {
        right[i] = R;
      }
      int breadth = right[i] - left[i] - 1;
      maxarea = Math.Max(maxarea, height * breadth);
    }
    return maxarea;
  }
 
  public static int MaxRectangleArea(int[, ] M, int R,
                                     int C)
  {
    int area = GetMaxArea(M, R, 0);
    int maxarea = area;
 
    for (int i = 1; i < R; i++) {
      for (int j = 0; j < C; j++) {
        if (M[i, j] != 0) {
          // Add heights of previous rows
          // into current
          M[i, j] = M[i, j] + M[i - 1, j];
        }
        else {
          // If current height is 0 then
          // don't add previous heights
          M[i, j] = 0;
        }
      }
      maxarea
        = Math.Max(maxarea, GetMaxArea(M, R, i));
    }
    return maxarea;
  }
 
  static public void Main()
  {
 
    // Code
    int[, ] amt = {
      { 0, 1, 1, 0 },
      { 1, 1, 1, 1 },
      { 1, 1, 1, 1 },
      { 1, 1, 0, 0 },
    };
    int R = 4, C = 4;
    Console.WriteLine(MaxRectangleArea(amt, R, C));
  }
}
 
// This code is contributed by lokeshmvs21.


Javascript




<script>
    // JavaScript code for the above approach:
 
    const INT_MIN = -2147483647 - 1;
 
    // Function to find next smaller element
    const nextsmallerelement = (arr, n) => {
 
        let st = [];
 
        // For the elements which dont have
        // next smaller element ans will be -1
        st.push(-1);
 
        // Store indices in output
        let right = new Array(n).fill(0);
 
        // Start from last index
        for (let i = n - 1; i >= 0; i--) {
 
            // If top element is sorted then
            // no need to do anything, just store
            // the answer and push the
            // current element in stack
            if ((st[st.length - 1] != -1)
                && arr[st[st.length - 1]] < arr[i]) {
                right[i] = st[st.length - 1];
                st.push(i);
            }
            else {
                while ((st[st.length - 1] != -1)
                    && arr[st[st.length - 1]]
                    >= arr[i]) {
                    st.pop();
                }
                right[i] = st[st.length - 1];
                st.push(i);
            }
        }
        return right;
    }
 
    // Function to find previous smaller element
    const previousmallerelement = (arr, n) => {
        let st = [];
        st.push(-1);
        let left = new Array(n).fill(0);
 
        // Start from first index
        for (let i = 0; i < n; i++) {
            if ((st[st.length - 1] != -1)
                && arr[st[st.length - 1]] < arr[i]) {
                left[i] = st[st.length - 1];
                st.push(i);
            }
            else {
                while ((st[st.length - 1] != -1)
                    && arr[st[st.length - 1]]
                    >= arr[i]) {
                    st.pop();
                }
                left[i] = st[st.length - 1];
                st.push(i);
            }
        }
        return left;
    }
 
    // Function to get the maximum area
    // considering each row as the histogram base
    const getMaxArea = (arr, n) => {
        let right = new Array(n).fill(0);
        right = nextsmallerelement(arr, n);
 
        // Find the smallest element than
        // curr element in right side
 
        let left = new Array(n).fill(0);
        left = previousmallerelement(arr, n);
 
        // Find the smallest element
        // than curr element in left side
        let maxarea = INT_MIN;
 
        // Now the left and right vector have
        // index of smallest element in left and
        // right respectively, thus the difference
        // of right - left - 1 will give us
        // breadth and thus
        // area = height(curr==arr[i]) * breadth;
        for (let i = 0; i < n; i++) {
            let height = arr[i];
            if (right[i] == -1) {
                right[i] = n;
            }
            let breadth = right[i] - left[i] - 1;
            maxarea = Math.max(maxarea,
                height * breadth);
        }
        return maxarea;
    }
 
    // Function to calculate
    // the maximum area of rectangle
    const maxRectangleArea = (M, n, m) => {
 
        // Calculate maxarea for first row
        let area = getMaxArea(M[0], m);
        let maxarea = area;
 
        for (let i = 1; i < n; i++) {
            for (let j = 0; j < m; j++) {
                if (M[i][j] != 0) {
 
                    // Add heights of previous rows
                    // into current
                    M[i][j] = M[i][j]
                        + M[i - 1][j];
                }
                else {
 
                    // If current height is 0 then
                    // don't add previous heights
                    M[i][j] = 0;
                }
            }
            maxarea = Math.max(maxarea,
                getMaxArea(M[i], m));
        }
        return maxarea;
    }
 
    // Driver code
 
    let N = 4, M = 4;
    let amt = [
        [0, 1, 1, 0],
        [1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 0, 0],
    ];
 
    document.write(maxRectangleArea(amt, N, M));
 
// This code is contributed by rakeshsahni
 
</script>


Output

8

Time Complexity: O(N * M)
Auxiliary Space: O(M)

This Article is Contributed by Rupesh Kapse



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