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 1Input: 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 0Calculate maxarea for the first row mat[0]
=> height row[0] = 0 1 1 0.
=> area = height* breadth = 1 * 2 = 2Calculate 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 = 4Calculate 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> |
8
Time Complexity: O(N * M)
Auxiliary Space: O(M)
This Article is Contributed by Rupesh Kapse.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!