Last Updated: 18 Dec, 2020

Maximum size subrectangle

Moderate
Asked in company
Adobe

Problem statement

You are given an 'N' * 'M' size binary-valued matrix, where 'N' is the number of rows and 'M' is the number of columns.

Your task is to return the size (area) of the maximum size submatrix which consists of all 1s i.e. the maximum area of a submatrix in which each cell has only the value ‘1’.

Note:
1. Binary-valued matrix has either 0 or 1 in each cell.
2. A submatrix is a matrix formed by selecting certain rows and columns from a larger matrix.

subMatrix_image

In the above image, areas in green, red, and violet colour are all submatrices of the original 4x4 matrix.

3. The area of a matrix with 'H' rows and 'W' columns is equal to 'H' * 'W'. 
Input Format:
The first line of the input contains an integer 'T' denoting the number of test cases.

The first line of each test case contains two space-separated integers 'N' and 'M'.

Then each of the next 'N' lines of each test case contains 'M' space-separated integers(either 1 or 0).
Output Format:
Print the area of maximum size submatrix of all 1s in the given matrix.

Print the output of each test case in a separate line.
Note:
You do not need to print anything, it has already been taken care of. Just implement the given function.
Constraints:
1 <= T <= 50
1 <= N, M <= 100

Time Limit: 1 sec

Approaches

01 Approach

  • The trick is to maintain a data structure that could mimic the function of the monotone increasing queue, which a stack can perform.
  • Suppose you have an input array height[0], height[1], height[2] ….,height[N-1].
    • Let’s suppose that we are at some index j, then we try to fix height[j] as the right side of the rectangle, then any of the heights { height[0] …. height[j-1] } in the monotone increasing queue can be the left side of the rectangle.
    • Before adding current height, i.e. height[j], to monotone increasing queue, for all the values in the queue that have height >= height[j] can be part of a rectangle of fixed height, height[j]. Thus, all such heights[i] are possible left sides of the current rectangle. Maximise the area of the rectangle possible in the histogram.
    • Pop all such heights from the queue and increase the breadth of the rectangle by 1. When there are no more elements to pop out of the queue. Push the current index in the queue, as it is guaranteed to follow monotone increasing height property.
  • Note that, if the histogram contains just one height, for such cases, initially push 0 to the queue to calculate maximum area.

 

The final algorithm will be-

  • At each row, we will maintain an additional 1- dimensional array height[] which denotes the height of contiguous 1’s at any column j, 0 <= j <= M-1, from bottom to top. Here bottom means current row i.
  • If the value of mat[i][j] = 0, then height[j] is set to 0, else it is incremented by 1.
  • This 1-dimensional height array at each row mimics the histogram. The only thing left is to apply the “Largest area in histogram” function to the updated height[] array in each row.
  • Maximise area at each step and return.

02 Approach

  • We start from the first row and move downwards.
  • We create three 1-dimensional arrays height[], left[], right[].

 

  1. height[i]: stores the number of current continuous 1’s in column i.
  2. left[i] : stores the leftmost index j such that all indices say k, k belongs to [j, i], height[k] >= height[i].
  3. right[i]: stores the rightmost index j such that all indices say k, k belongs to [i, j], height[k] >= height[i].

 

  • By the above definitions, it’s easier to figure out that we can update our maximum area with the value (height[i] * (right[i] - left[i])).
  • We can update all the 1-dimensional arrays/lists in linear time complexities. We will initialize the height and left array with 0, and right array with ‘M’.

 

  • We can update the height array/list as:
    • Iterate through the rows from 0 to N-1.
    • For each column:
      • If the current value (mat[i][j]) is 1, then update height[j]++.
      • Else, reset the value of height[j] to 0.

 

  • Updating the left[] array in each iteration among rows 0 to N-1:
    • We scan from left to right.
    • Initialise leftBoundary = 0, which means left boundary for all 1’s in the current row.
    • Iterate in the current row:
      • If the current value  (mat[i][j]) is 1, then you can reset the left[j] from 0 to leftBoundary.
      • Else,
        • Update left[j] to 0 and leftBoundary to j + 1.
        • As the current value is 0, so the next leftBoundary for all the cells in the matrix ahead of column j is at least j + 1.

 

  • Similarly, for the right[] array  in each iteration among rows 0 to N-1:
    • We scan from right to left.
    • Initialise rightBoundary = 0, which means right boundary for all 1’s in the current row.
    • Iterate in the current row:
      • If the current value  (mat[i][j]) is 1, then you can reset the right[j] from M to rightBoundary.
      • Else,
        • Update right[j] to 0 and rightBoundary to j - 1.
        • As the current value is 0, so the next rightBoundary for all the cells in the matrix before column j is at most j - 1.