Find largest rectangle containing only zeros in an N×N binary matrix












66














Given an NxN binary matrix (containing only 0's or 1's), how can we go about finding largest rectangle containing all 0's?



Example:



      I
0 0 0 0 1 0
0 0 1 0 0 1
II->0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1 <--IV
0 0 1 0 0 0
IV


For the above example, it is a 6×6 binary matrix. the return value in this case will be Cell 1:(2, 1) and Cell 2:(4, 4). The resulting sub-matrix can be square or rectangular. The return value can also be the size of the largest sub-matrix of all 0's, in this example 3 × 4.










share|improve this question




















  • 1




    Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
    – j_random_hacker
    Jan 15 '11 at 4:18






  • 1




    Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
    – TMS
    Mar 29 '12 at 20:15












  • I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
    – Chris Maes
    Mar 24 '14 at 8:16










  • @TMS It's actually the other way around. Those questions are duplicates of this one.
    – tommy.carstensen
    May 24 '15 at 0:46
















66














Given an NxN binary matrix (containing only 0's or 1's), how can we go about finding largest rectangle containing all 0's?



Example:



      I
0 0 0 0 1 0
0 0 1 0 0 1
II->0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1 <--IV
0 0 1 0 0 0
IV


For the above example, it is a 6×6 binary matrix. the return value in this case will be Cell 1:(2, 1) and Cell 2:(4, 4). The resulting sub-matrix can be square or rectangular. The return value can also be the size of the largest sub-matrix of all 0's, in this example 3 × 4.










share|improve this question




















  • 1




    Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
    – j_random_hacker
    Jan 15 '11 at 4:18






  • 1




    Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
    – TMS
    Mar 29 '12 at 20:15












  • I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
    – Chris Maes
    Mar 24 '14 at 8:16










  • @TMS It's actually the other way around. Those questions are duplicates of this one.
    – tommy.carstensen
    May 24 '15 at 0:46














66












66








66


56





Given an NxN binary matrix (containing only 0's or 1's), how can we go about finding largest rectangle containing all 0's?



Example:



      I
0 0 0 0 1 0
0 0 1 0 0 1
II->0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1 <--IV
0 0 1 0 0 0
IV


For the above example, it is a 6×6 binary matrix. the return value in this case will be Cell 1:(2, 1) and Cell 2:(4, 4). The resulting sub-matrix can be square or rectangular. The return value can also be the size of the largest sub-matrix of all 0's, in this example 3 × 4.










share|improve this question















Given an NxN binary matrix (containing only 0's or 1's), how can we go about finding largest rectangle containing all 0's?



Example:



      I
0 0 0 0 1 0
0 0 1 0 0 1
II->0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1 <--IV
0 0 1 0 0 0
IV


For the above example, it is a 6×6 binary matrix. the return value in this case will be Cell 1:(2, 1) and Cell 2:(4, 4). The resulting sub-matrix can be square or rectangular. The return value can also be the size of the largest sub-matrix of all 0's, in this example 3 × 4.







algorithm arrays






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 15 '14 at 21:41









DevNull

11.8k847103




11.8k847103










asked Mar 19 '10 at 15:24









Rajendra Uppal

7,633104856




7,633104856








  • 1




    Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
    – j_random_hacker
    Jan 15 '11 at 4:18






  • 1




    Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
    – TMS
    Mar 29 '12 at 20:15












  • I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
    – Chris Maes
    Mar 24 '14 at 8:16










  • @TMS It's actually the other way around. Those questions are duplicates of this one.
    – tommy.carstensen
    May 24 '15 at 0:46














  • 1




    Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
    – j_random_hacker
    Jan 15 '11 at 4:18






  • 1




    Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
    – TMS
    Mar 29 '12 at 20:15












  • I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
    – Chris Maes
    Mar 24 '14 at 8:16










  • @TMS It's actually the other way around. Those questions are duplicates of this one.
    – tommy.carstensen
    May 24 '15 at 0:46








1




1




Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
– j_random_hacker
Jan 15 '11 at 4:18




Please consider changing the accepted answer to J.F. Sebastian's answer, which is now correct and has optimal complexity.
– j_random_hacker
Jan 15 '11 at 4:18




1




1




Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
– TMS
Mar 29 '12 at 20:15






Please check very similar (I'd say duplicate) questions: stackoverflow.com/questions/7770945/… , stackoverflow.com/a/7353193/684229 . The solution is O(n).
– TMS
Mar 29 '12 at 20:15














I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
– Chris Maes
Mar 24 '14 at 8:16




I'm trying to do the same with a rectangle oriented in any direction. see question: stackoverflow.com/questions/22604043/…
– Chris Maes
Mar 24 '14 at 8:16












@TMS It's actually the other way around. Those questions are duplicates of this one.
– tommy.carstensen
May 24 '15 at 0:46




@TMS It's actually the other way around. Those questions are duplicates of this one.
– tommy.carstensen
May 24 '15 at 0:46












7 Answers
7






active

oldest

votes


















38














Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by @j_random_hacker in the comments:




[Algorithm] works by iterating through
rows from top to bottom, for each row
solving this problem, where the
"bars" in the "histogram" consist of
all unbroken upward trails of zeros
that start at the current row (a
column has height 0 if it has a 1 in
the current row).




The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.



#!/usr/bin/env python
from collections import namedtuple
from operator import mul

Info = namedtuple('Info', 'start height')

def max_size(mat, value=0):
"""Find height, width of the largest rectangle containing all `value`'s."""
it = iter(mat)
hist = [(el==value) for el in next(it, )]
max_size = max_rectangle_size(hist)
for row in it:
hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
max_size = max(max_size, max_rectangle_size(hist), key=area)
return max_size

def max_rectangle_size(histogram):
"""Find height, width of the largest rectangle that fits entirely under
the histogram.
"""
stack =
top = lambda: stack[-1]
max_size = (0, 0) # height, width of the largest rectangle
pos = 0 # current position in the histogram
for pos, height in enumerate(histogram):
start = pos # position where rectangle starts
while True:
if not stack or height > top().height:
stack.append(Info(start, height)) # push
elif stack and height < top().height:
max_size = max(max_size, (top().height, (pos - top().start)),
key=area)
start, _ = stack.pop()
continue
break # height == top().height goes here

pos += 1
for start, height in stack:
max_size = max(max_size, (height, (pos - start)), key=area)
return max_size

def area(size):
return reduce(mul, size)


The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.



Latest version with tests is at https://gist.github.com/776423






share|improve this answer



















  • 2




    Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
    – j_random_hacker
    Jan 14 '11 at 2:02






  • 3




    The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
    – j_random_hacker
    Jan 14 '11 at 2:08






  • 6




    @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
    – jfs
    Jan 14 '11 at 12:45






  • 1




    Looks good, +2! :)
    – j_random_hacker
    Jan 15 '11 at 4:14






  • 4




    This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
    – JBWhitmore
    Jan 26 '14 at 3:25



















27














Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.



Traverse the matrix once and store the following;

For x=1 to N and y=1 to N
F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0

Then for each row for x=N to 1
We have F[x] -> array with heights of the histograms with base at x.
Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]

From all areas computed, report the largest.


Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)



Example:



Initial array    F[x][y] array
0 0 0 0 1 0 1 1 1 1 0 1
0 0 1 0 0 1 2 2 0 2 1 0
0 0 0 0 0 0 3 3 1 3 2 1
1 0 0 0 0 0 0 4 2 4 3 2
0 0 0 0 0 1 1 5 3 5 4 0
0 0 1 0 0 0 2 6 0 6 5 1

For x = N to 1
H[6] = 2 6 0 6 5 1 -> 10 (5*2)
H[5] = 1 5 3 5 4 0 -> 12 (3*4)
H[4] = 0 4 2 4 3 2 -> 10 (2*5)
H[3] = 3 3 1 3 2 1 -> 6 (3*2)
H[2] = 2 2 0 2 1 0 -> 4 (2*2)
H[1] = 1 1 1 1 0 1 -> 4 (1*4)

The largest area is thus H[5] = 12





share|improve this answer























  • nice explanation with example
    – Peter
    Jan 22 '13 at 15:00






  • 1




    are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
    – Chris Maes
    Mar 21 '14 at 10:26












  • very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
    – knocker
    Oct 2 '15 at 15:26






  • 1




    To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
    – user2469515
    Apr 17 '16 at 2:19





















9














Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:



#!/usr/bin/env python3

import numpy

s = '''0 0 0 0 1 0
0 0 1 0 0 1
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1
0 0 1 0 0 0'''

nrows = 6
ncols = 6
skip = 1
area_max = (0, )

a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
w = numpy.zeros(dtype=int, shape=a.shape)
h = numpy.zeros(dtype=int, shape=a.shape)
for r in range(nrows):
for c in range(ncols):
if a[r][c] == skip:
continue
if r == 0:
h[r][c] = 1
else:
h[r][c] = h[r-1][c]+1
if c == 0:
w[r][c] = 1
else:
w[r][c] = w[r][c-1]+1
minw = w[r][c]
for dh in range(h[r][c]):
minw = min(minw, w[r-dh][c])
area = (dh+1)*minw
if area > area_max[0]:
area_max = (area, [(r-dh, c-minw+1, r, c)])

print('area', area_max[0])
for t in area_max[1]:
print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))


Output:



area 12
Cell 1:(2, 1) and Cell 2:(4, 4)





share|improve this answer































    3














    Here is J.F. Sebastians method translated into C#:



    private Vector2 MaxRectSize(int histogram) {
    Vector2 maxSize = Vector2.zero;
    int maxArea = 0;
    Stack<Vector2> stack = new Stack<Vector2>();

    int x = 0;
    for (x = 0; x < histogram.Length; x++) {
    int start = x;
    int height = histogram[x];
    while (true) {
    if (stack.Count == 0 || height > stack.Peek().y) {
    stack.Push(new Vector2(start, height));

    } else if(height < stack.Peek().y) {
    int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
    if(tempArea > maxArea) {
    maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
    maxArea = tempArea;
    }

    Vector2 popped = stack.Pop();
    start = (int)popped.x;
    continue;
    }

    break;
    }
    }

    foreach (Vector2 data in stack) {
    int tempArea = (int)(data.y * (x - data.x));
    if(tempArea > maxArea) {
    maxSize = new Vector2(data.y, (x - data.x));
    maxArea = tempArea;
    }
    }

    return maxSize;
    }

    public Vector2 GetMaximumFreeSpace() {
    // STEP 1:
    // build a seed histogram using the first row of grid points
    // example: [true, true, false, true] = [1,1,0,1]
    int hist = new int[gridSizeY];
    for (int y = 0; y < gridSizeY; y++) {
    if(!invalidPoints[0, y]) {
    hist[y] = 1;
    }
    }

    // STEP 2:
    // get a starting max area from the seed histogram we created above.
    // using the example from above, this value would be [1, 1], as the only valid area is a single point.
    // another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
    // Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
    // a single row of data.
    Vector2 maxSize = MaxRectSize(hist);
    int maxArea = (int)(maxSize.x * maxSize.y);

    // STEP 3:
    // build histograms for each additional row, re-testing for new possible max rectangluar areas
    for (int x = 1; x < gridSizeX; x++) {
    // build a new histogram for this row. the values of this row are
    // 0 if the current grid point is occupied; otherwise, it is 1 + the value
    // of the previously found historgram value for the previous position.
    // What this does is effectly keep track of the height of continous avilable spaces.
    // EXAMPLE:
    // Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
    // INPUT: OUTPUT:
    // 1.) [0,0,1,0] = [1,1,0,1]
    // 2.) [0,0,1,0] = [2,2,0,2]
    // 3.) [1,1,0,1] = [0,0,1,0]
    //
    // As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
    // free space.
    for (int y = 0; y < gridSizeY; y++) {
    if(!invalidPoints[x, y]) {
    hist[y] = 1 + hist[y];
    } else {
    hist[y] = 0;
    }
    }

    // find the maximum size of the current histogram. If it happens to be larger
    // that the currently recorded max size, then it is the new max size.
    Vector2 maxSizeTemp = MaxRectSize(hist);
    int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
    if (tempArea > maxArea) {
    maxSize = maxSizeTemp;
    maxArea = tempArea;
    }
    }

    // at this point, we know the max size
    return maxSize;
    }


    A few things to note about this:




    1. This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.

    2. invalidPoints is an array of bool, where true means the grid point is "in use", and false means it is not.






    share|improve this answer





























      3














      Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)



      public int maximalRectangle(char matrix) {
      int m = matrix.length;
      if (m == 0)
      return 0;
      int n = matrix[0].length;
      int maxArea = 0;
      int aux = new int[n];
      for (int i = 0; i < n; i++) {
      aux[i] = 0;
      }
      for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
      aux[j] = matrix[i][j] - '0' + aux[j];
      maxArea = Math.max(maxArea, maxAreaHist(aux));
      }
      }
      return maxArea;
      }

      public int maxAreaHist(int heights) {
      int n = heights.length;
      Stack<Integer> stack = new Stack<Integer>();
      stack.push(0);
      int maxRect = heights[0];
      int top = 0;
      int leftSideArea = 0;
      int rightSideArea = heights[0];
      for (int i = 1; i < n; i++) {
      if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
      stack.push(i);
      } else {
      while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
      top = stack.pop();
      rightSideArea = heights[top] * (i - top);
      leftSideArea = 0;
      if (!stack.isEmpty()) {
      leftSideArea = heights[top] * (top - stack.peek() - 1);
      } else {
      leftSideArea = heights[top] * top;
      }
      maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
      }
      stack.push(i);
      }
      }
      while (!stack.isEmpty()) {
      top = stack.pop();
      rightSideArea = heights[top] * (n - top);
      leftSideArea = 0;
      if (!stack.isEmpty()) {
      leftSideArea = heights[top] * (top - stack.peek() - 1);
      } else {
      leftSideArea = heights[top] * top;
      }
      maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
      }
      return maxRect;
      }


      But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?






      share|improve this answer





















      • Input at leet code has 200 rows and 200 columns
        – Astha Gupta
        May 14 '16 at 8:13










      • Simple and easy to understand.. Thank you!
        – Swadhikar C
        Jul 9 '16 at 4:02



















      2














      I propose a O(nxn) method.



      First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.



      A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).



      Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).



      Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).



      In practice, this method is very fast, and is used for realtime video stream analysis.






      share|improve this answer































        0














        Here is a version of jfs' solution, which also delivers the position of the largest rectangle:



        from collections import namedtuple
        from operator import mul

        Info = namedtuple('Info', 'start height')

        def max_rect(mat, value=0):
        """returns (height, width, left_column, bottom_row) of the largest rectangle
        containing all `value`'s.

        Example:
        [[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
        [0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
        [1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
        [0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
        [0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
        [4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
        [3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
        [0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
        [0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
        gives: (3, 4, 6, 5)
        """
        it = iter(mat)
        hist = [(el==value) for el in next(it, )]
        max_rect = max_rectangle_size(hist) + (0,)
        for irow,row in enumerate(it):
        hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
        max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
        # irow+1, because we already used one row for initializing max_rect
        return max_rect

        def max_rectangle_size(histogram):
        stack =
        top = lambda: stack[-1]
        max_size = (0, 0, 0) # height, width and start position of the largest rectangle
        pos = 0 # current position in the histogram
        for pos, height in enumerate(histogram):
        start = pos # position where rectangle starts
        while True:
        if not stack or height > top().height:
        stack.append(Info(start, height)) # push
        elif stack and height < top().height:
        max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
        start, _ = stack.pop()
        continue
        break # height == top().height goes here

        pos += 1
        for start, height in stack:
        max_size = max(max_size, (height, (pos - start), start), key=area)

        return max_size

        def area(size):
        return size[0] * size[1]





        share|improve this answer























          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2478447%2ffind-largest-rectangle-containing-only-zeros-in-an-n%25c3%2597n-binary-matrix%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          7 Answers
          7






          active

          oldest

          votes








          7 Answers
          7






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          38














          Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by @j_random_hacker in the comments:




          [Algorithm] works by iterating through
          rows from top to bottom, for each row
          solving this problem, where the
          "bars" in the "histogram" consist of
          all unbroken upward trails of zeros
          that start at the current row (a
          column has height 0 if it has a 1 in
          the current row).




          The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.



          #!/usr/bin/env python
          from collections import namedtuple
          from operator import mul

          Info = namedtuple('Info', 'start height')

          def max_size(mat, value=0):
          """Find height, width of the largest rectangle containing all `value`'s."""
          it = iter(mat)
          hist = [(el==value) for el in next(it, )]
          max_size = max_rectangle_size(hist)
          for row in it:
          hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
          max_size = max(max_size, max_rectangle_size(hist), key=area)
          return max_size

          def max_rectangle_size(histogram):
          """Find height, width of the largest rectangle that fits entirely under
          the histogram.
          """
          stack =
          top = lambda: stack[-1]
          max_size = (0, 0) # height, width of the largest rectangle
          pos = 0 # current position in the histogram
          for pos, height in enumerate(histogram):
          start = pos # position where rectangle starts
          while True:
          if not stack or height > top().height:
          stack.append(Info(start, height)) # push
          elif stack and height < top().height:
          max_size = max(max_size, (top().height, (pos - top().start)),
          key=area)
          start, _ = stack.pop()
          continue
          break # height == top().height goes here

          pos += 1
          for start, height in stack:
          max_size = max(max_size, (height, (pos - start)), key=area)
          return max_size

          def area(size):
          return reduce(mul, size)


          The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.



          Latest version with tests is at https://gist.github.com/776423






          share|improve this answer



















          • 2




            Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
            – j_random_hacker
            Jan 14 '11 at 2:02






          • 3




            The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
            – j_random_hacker
            Jan 14 '11 at 2:08






          • 6




            @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
            – jfs
            Jan 14 '11 at 12:45






          • 1




            Looks good, +2! :)
            – j_random_hacker
            Jan 15 '11 at 4:14






          • 4




            This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
            – JBWhitmore
            Jan 26 '14 at 3:25
















          38














          Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by @j_random_hacker in the comments:




          [Algorithm] works by iterating through
          rows from top to bottom, for each row
          solving this problem, where the
          "bars" in the "histogram" consist of
          all unbroken upward trails of zeros
          that start at the current row (a
          column has height 0 if it has a 1 in
          the current row).




          The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.



          #!/usr/bin/env python
          from collections import namedtuple
          from operator import mul

          Info = namedtuple('Info', 'start height')

          def max_size(mat, value=0):
          """Find height, width of the largest rectangle containing all `value`'s."""
          it = iter(mat)
          hist = [(el==value) for el in next(it, )]
          max_size = max_rectangle_size(hist)
          for row in it:
          hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
          max_size = max(max_size, max_rectangle_size(hist), key=area)
          return max_size

          def max_rectangle_size(histogram):
          """Find height, width of the largest rectangle that fits entirely under
          the histogram.
          """
          stack =
          top = lambda: stack[-1]
          max_size = (0, 0) # height, width of the largest rectangle
          pos = 0 # current position in the histogram
          for pos, height in enumerate(histogram):
          start = pos # position where rectangle starts
          while True:
          if not stack or height > top().height:
          stack.append(Info(start, height)) # push
          elif stack and height < top().height:
          max_size = max(max_size, (top().height, (pos - top().start)),
          key=area)
          start, _ = stack.pop()
          continue
          break # height == top().height goes here

          pos += 1
          for start, height in stack:
          max_size = max(max_size, (height, (pos - start)), key=area)
          return max_size

          def area(size):
          return reduce(mul, size)


          The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.



          Latest version with tests is at https://gist.github.com/776423






          share|improve this answer



















          • 2




            Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
            – j_random_hacker
            Jan 14 '11 at 2:02






          • 3




            The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
            – j_random_hacker
            Jan 14 '11 at 2:08






          • 6




            @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
            – jfs
            Jan 14 '11 at 12:45






          • 1




            Looks good, +2! :)
            – j_random_hacker
            Jan 15 '11 at 4:14






          • 4




            This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
            – JBWhitmore
            Jan 26 '14 at 3:25














          38












          38








          38






          Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by @j_random_hacker in the comments:




          [Algorithm] works by iterating through
          rows from top to bottom, for each row
          solving this problem, where the
          "bars" in the "histogram" consist of
          all unbroken upward trails of zeros
          that start at the current row (a
          column has height 0 if it has a 1 in
          the current row).




          The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.



          #!/usr/bin/env python
          from collections import namedtuple
          from operator import mul

          Info = namedtuple('Info', 'start height')

          def max_size(mat, value=0):
          """Find height, width of the largest rectangle containing all `value`'s."""
          it = iter(mat)
          hist = [(el==value) for el in next(it, )]
          max_size = max_rectangle_size(hist)
          for row in it:
          hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
          max_size = max(max_size, max_rectangle_size(hist), key=area)
          return max_size

          def max_rectangle_size(histogram):
          """Find height, width of the largest rectangle that fits entirely under
          the histogram.
          """
          stack =
          top = lambda: stack[-1]
          max_size = (0, 0) # height, width of the largest rectangle
          pos = 0 # current position in the histogram
          for pos, height in enumerate(histogram):
          start = pos # position where rectangle starts
          while True:
          if not stack or height > top().height:
          stack.append(Info(start, height)) # push
          elif stack and height < top().height:
          max_size = max(max_size, (top().height, (pos - top().start)),
          key=area)
          start, _ = stack.pop()
          continue
          break # height == top().height goes here

          pos += 1
          for start, height in stack:
          max_size = max(max_size, (height, (pos - start)), key=area)
          return max_size

          def area(size):
          return reduce(mul, size)


          The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.



          Latest version with tests is at https://gist.github.com/776423






          share|improve this answer














          Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by @j_random_hacker in the comments:




          [Algorithm] works by iterating through
          rows from top to bottom, for each row
          solving this problem, where the
          "bars" in the "histogram" consist of
          all unbroken upward trails of zeros
          that start at the current row (a
          column has height 0 if it has a 1 in
          the current row).




          The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.



          #!/usr/bin/env python
          from collections import namedtuple
          from operator import mul

          Info = namedtuple('Info', 'start height')

          def max_size(mat, value=0):
          """Find height, width of the largest rectangle containing all `value`'s."""
          it = iter(mat)
          hist = [(el==value) for el in next(it, )]
          max_size = max_rectangle_size(hist)
          for row in it:
          hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
          max_size = max(max_size, max_rectangle_size(hist), key=area)
          return max_size

          def max_rectangle_size(histogram):
          """Find height, width of the largest rectangle that fits entirely under
          the histogram.
          """
          stack =
          top = lambda: stack[-1]
          max_size = (0, 0) # height, width of the largest rectangle
          pos = 0 # current position in the histogram
          for pos, height in enumerate(histogram):
          start = pos # position where rectangle starts
          while True:
          if not stack or height > top().height:
          stack.append(Info(start, height)) # push
          elif stack and height < top().height:
          max_size = max(max_size, (top().height, (pos - top().start)),
          key=area)
          start, _ = stack.pop()
          continue
          break # height == top().height goes here

          pos += 1
          for start, height in stack:
          max_size = max(max_size, (height, (pos - start)), key=area)
          return max_size

          def area(size):
          return reduce(mul, size)


          The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.



          Latest version with tests is at https://gist.github.com/776423







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 23 '17 at 10:31









          Community

          11




          11










          answered Jan 12 '11 at 16:40









          jfs

          261k765461074




          261k765461074








          • 2




            Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
            – j_random_hacker
            Jan 14 '11 at 2:02






          • 3




            The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
            – j_random_hacker
            Jan 14 '11 at 2:08






          • 6




            @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
            – jfs
            Jan 14 '11 at 12:45






          • 1




            Looks good, +2! :)
            – j_random_hacker
            Jan 15 '11 at 4:14






          • 4




            This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
            – JBWhitmore
            Jan 26 '14 at 3:25














          • 2




            Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
            – j_random_hacker
            Jan 14 '11 at 2:02






          • 3




            The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
            – j_random_hacker
            Jan 14 '11 at 2:08






          • 6




            @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
            – jfs
            Jan 14 '11 at 12:45






          • 1




            Looks good, +2! :)
            – j_random_hacker
            Jan 15 '11 at 4:14






          • 4




            This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
            – JBWhitmore
            Jan 26 '14 at 3:25








          2




          2




          Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
          – j_random_hacker
          Jan 14 '11 at 2:02




          Good try, but this fails max_size([[0,0,0,0,1,1,1], [0,0,0,0,0,0,0], [0,0,0,1,1,1,1], [0,0,1,1,1,1,1]] + [[1,0,1,1,1,1,1]] * 3), returning (2, 4) when there is a 3x3 square in the top left.
          – j_random_hacker
          Jan 14 '11 at 2:02




          3




          3




          The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
          – j_random_hacker
          Jan 14 '11 at 2:08




          The basic problem is that it's not always sufficient to track just (several) largest-area rectangles of neighbouring points as you're doing here. The only O(N) algorithm that I know to be correct works by iterating through rows from top to bottom, for each row solving this problem: stackoverflow.com/questions/4311694/…, where the "bars" in the "histogram" consist of all unbroken upward trails of zeros that start at the current row (a column has height 0 if it has a 1 in the current row).
          – j_random_hacker
          Jan 14 '11 at 2:08




          6




          6




          @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
          – jfs
          Jan 14 '11 at 12:45




          @j_random_hacker: I've updated my answer to use "histogram"-based algorithm.
          – jfs
          Jan 14 '11 at 12:45




          1




          1




          Looks good, +2! :)
          – j_random_hacker
          Jan 15 '11 at 4:14




          Looks good, +2! :)
          – j_random_hacker
          Jan 15 '11 at 4:14




          4




          4




          This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
          – JBWhitmore
          Jan 26 '14 at 3:25




          This looks great, however, I'm trying to actually FIND the largest rectangle (as in, return the coordinates). This algorithm will reliably return the area, but once I know that, how would a person discover that the location of a 3 column x 2 row rectangle, with its upper-left corner at [3, 5] (for example)?
          – JBWhitmore
          Jan 26 '14 at 3:25













          27














          Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.



          Traverse the matrix once and store the following;

          For x=1 to N and y=1 to N
          F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0

          Then for each row for x=N to 1
          We have F[x] -> array with heights of the histograms with base at x.
          Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]

          From all areas computed, report the largest.


          Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)



          Example:



          Initial array    F[x][y] array
          0 0 0 0 1 0 1 1 1 1 0 1
          0 0 1 0 0 1 2 2 0 2 1 0
          0 0 0 0 0 0 3 3 1 3 2 1
          1 0 0 0 0 0 0 4 2 4 3 2
          0 0 0 0 0 1 1 5 3 5 4 0
          0 0 1 0 0 0 2 6 0 6 5 1

          For x = N to 1
          H[6] = 2 6 0 6 5 1 -> 10 (5*2)
          H[5] = 1 5 3 5 4 0 -> 12 (3*4)
          H[4] = 0 4 2 4 3 2 -> 10 (2*5)
          H[3] = 3 3 1 3 2 1 -> 6 (3*2)
          H[2] = 2 2 0 2 1 0 -> 4 (2*2)
          H[1] = 1 1 1 1 0 1 -> 4 (1*4)

          The largest area is thus H[5] = 12





          share|improve this answer























          • nice explanation with example
            – Peter
            Jan 22 '13 at 15:00






          • 1




            are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
            – Chris Maes
            Mar 21 '14 at 10:26












          • very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
            – knocker
            Oct 2 '15 at 15:26






          • 1




            To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
            – user2469515
            Apr 17 '16 at 2:19


















          27














          Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.



          Traverse the matrix once and store the following;

          For x=1 to N and y=1 to N
          F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0

          Then for each row for x=N to 1
          We have F[x] -> array with heights of the histograms with base at x.
          Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]

          From all areas computed, report the largest.


          Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)



          Example:



          Initial array    F[x][y] array
          0 0 0 0 1 0 1 1 1 1 0 1
          0 0 1 0 0 1 2 2 0 2 1 0
          0 0 0 0 0 0 3 3 1 3 2 1
          1 0 0 0 0 0 0 4 2 4 3 2
          0 0 0 0 0 1 1 5 3 5 4 0
          0 0 1 0 0 0 2 6 0 6 5 1

          For x = N to 1
          H[6] = 2 6 0 6 5 1 -> 10 (5*2)
          H[5] = 1 5 3 5 4 0 -> 12 (3*4)
          H[4] = 0 4 2 4 3 2 -> 10 (2*5)
          H[3] = 3 3 1 3 2 1 -> 6 (3*2)
          H[2] = 2 2 0 2 1 0 -> 4 (2*2)
          H[1] = 1 1 1 1 0 1 -> 4 (1*4)

          The largest area is thus H[5] = 12





          share|improve this answer























          • nice explanation with example
            – Peter
            Jan 22 '13 at 15:00






          • 1




            are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
            – Chris Maes
            Mar 21 '14 at 10:26












          • very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
            – knocker
            Oct 2 '15 at 15:26






          • 1




            To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
            – user2469515
            Apr 17 '16 at 2:19
















          27












          27








          27






          Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.



          Traverse the matrix once and store the following;

          For x=1 to N and y=1 to N
          F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0

          Then for each row for x=N to 1
          We have F[x] -> array with heights of the histograms with base at x.
          Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]

          From all areas computed, report the largest.


          Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)



          Example:



          Initial array    F[x][y] array
          0 0 0 0 1 0 1 1 1 1 0 1
          0 0 1 0 0 1 2 2 0 2 1 0
          0 0 0 0 0 0 3 3 1 3 2 1
          1 0 0 0 0 0 0 4 2 4 3 2
          0 0 0 0 0 1 1 5 3 5 4 0
          0 0 1 0 0 0 2 6 0 6 5 1

          For x = N to 1
          H[6] = 2 6 0 6 5 1 -> 10 (5*2)
          H[5] = 1 5 3 5 4 0 -> 12 (3*4)
          H[4] = 0 4 2 4 3 2 -> 10 (2*5)
          H[3] = 3 3 1 3 2 1 -> 6 (3*2)
          H[2] = 2 2 0 2 1 0 -> 4 (2*2)
          H[1] = 1 1 1 1 0 1 -> 4 (1*4)

          The largest area is thus H[5] = 12





          share|improve this answer














          Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.



          Traverse the matrix once and store the following;

          For x=1 to N and y=1 to N
          F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0

          Then for each row for x=N to 1
          We have F[x] -> array with heights of the histograms with base at x.
          Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]

          From all areas computed, report the largest.


          Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)



          Example:



          Initial array    F[x][y] array
          0 0 0 0 1 0 1 1 1 1 0 1
          0 0 1 0 0 1 2 2 0 2 1 0
          0 0 0 0 0 0 3 3 1 3 2 1
          1 0 0 0 0 0 0 4 2 4 3 2
          0 0 0 0 0 1 1 5 3 5 4 0
          0 0 1 0 0 0 2 6 0 6 5 1

          For x = N to 1
          H[6] = 2 6 0 6 5 1 -> 10 (5*2)
          H[5] = 1 5 3 5 4 0 -> 12 (3*4)
          H[4] = 0 4 2 4 3 2 -> 10 (2*5)
          H[3] = 3 3 1 3 2 1 -> 6 (3*2)
          H[2] = 2 2 0 2 1 0 -> 4 (2*2)
          H[1] = 1 1 1 1 0 1 -> 4 (1*4)

          The largest area is thus H[5] = 12






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 23 '17 at 12:34









          Community

          11




          11










          answered Sep 12 '12 at 11:29









          Sajal Jain

          618514




          618514












          • nice explanation with example
            – Peter
            Jan 22 '13 at 15:00






          • 1




            are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
            – Chris Maes
            Mar 21 '14 at 10:26












          • very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
            – knocker
            Oct 2 '15 at 15:26






          • 1




            To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
            – user2469515
            Apr 17 '16 at 2:19




















          • nice explanation with example
            – Peter
            Jan 22 '13 at 15:00






          • 1




            are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
            – Chris Maes
            Mar 21 '14 at 10:26












          • very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
            – knocker
            Oct 2 '15 at 15:26






          • 1




            To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
            – user2469515
            Apr 17 '16 at 2:19


















          nice explanation with example
          – Peter
          Jan 22 '13 at 15:00




          nice explanation with example
          – Peter
          Jan 22 '13 at 15:00




          1




          1




          are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
          – Chris Maes
          Mar 21 '14 at 10:26






          are you sure this is O(N*N)? There are two passes over the whole matrix, but my impression is this is O(N).
          – Chris Maes
          Mar 21 '14 at 10:26














          very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
          – knocker
          Oct 2 '15 at 15:26




          very nice explanation.. :) I wish, you would have explained "Maximize the rectangular area under Histogram" too.. :D
          – knocker
          Oct 2 '15 at 15:26




          1




          1




          To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
          – user2469515
          Apr 17 '16 at 2:19






          To make it more clear. The solution is O(N*N), where N is the number of items in a row/col since the question states the input is NxN in size. If N was the total number of items in the input, then it is O(N)
          – user2469515
          Apr 17 '16 at 2:19













          9














          Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:



          #!/usr/bin/env python3

          import numpy

          s = '''0 0 0 0 1 0
          0 0 1 0 0 1
          0 0 0 0 0 0
          1 0 0 0 0 0
          0 0 0 0 0 1
          0 0 1 0 0 0'''

          nrows = 6
          ncols = 6
          skip = 1
          area_max = (0, )

          a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
          w = numpy.zeros(dtype=int, shape=a.shape)
          h = numpy.zeros(dtype=int, shape=a.shape)
          for r in range(nrows):
          for c in range(ncols):
          if a[r][c] == skip:
          continue
          if r == 0:
          h[r][c] = 1
          else:
          h[r][c] = h[r-1][c]+1
          if c == 0:
          w[r][c] = 1
          else:
          w[r][c] = w[r][c-1]+1
          minw = w[r][c]
          for dh in range(h[r][c]):
          minw = min(minw, w[r-dh][c])
          area = (dh+1)*minw
          if area > area_max[0]:
          area_max = (area, [(r-dh, c-minw+1, r, c)])

          print('area', area_max[0])
          for t in area_max[1]:
          print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))


          Output:



          area 12
          Cell 1:(2, 1) and Cell 2:(4, 4)





          share|improve this answer




























            9














            Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:



            #!/usr/bin/env python3

            import numpy

            s = '''0 0 0 0 1 0
            0 0 1 0 0 1
            0 0 0 0 0 0
            1 0 0 0 0 0
            0 0 0 0 0 1
            0 0 1 0 0 0'''

            nrows = 6
            ncols = 6
            skip = 1
            area_max = (0, )

            a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
            w = numpy.zeros(dtype=int, shape=a.shape)
            h = numpy.zeros(dtype=int, shape=a.shape)
            for r in range(nrows):
            for c in range(ncols):
            if a[r][c] == skip:
            continue
            if r == 0:
            h[r][c] = 1
            else:
            h[r][c] = h[r-1][c]+1
            if c == 0:
            w[r][c] = 1
            else:
            w[r][c] = w[r][c-1]+1
            minw = w[r][c]
            for dh in range(h[r][c]):
            minw = min(minw, w[r-dh][c])
            area = (dh+1)*minw
            if area > area_max[0]:
            area_max = (area, [(r-dh, c-minw+1, r, c)])

            print('area', area_max[0])
            for t in area_max[1]:
            print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))


            Output:



            area 12
            Cell 1:(2, 1) and Cell 2:(4, 4)





            share|improve this answer


























              9












              9








              9






              Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:



              #!/usr/bin/env python3

              import numpy

              s = '''0 0 0 0 1 0
              0 0 1 0 0 1
              0 0 0 0 0 0
              1 0 0 0 0 0
              0 0 0 0 0 1
              0 0 1 0 0 0'''

              nrows = 6
              ncols = 6
              skip = 1
              area_max = (0, )

              a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
              w = numpy.zeros(dtype=int, shape=a.shape)
              h = numpy.zeros(dtype=int, shape=a.shape)
              for r in range(nrows):
              for c in range(ncols):
              if a[r][c] == skip:
              continue
              if r == 0:
              h[r][c] = 1
              else:
              h[r][c] = h[r-1][c]+1
              if c == 0:
              w[r][c] = 1
              else:
              w[r][c] = w[r][c-1]+1
              minw = w[r][c]
              for dh in range(h[r][c]):
              minw = min(minw, w[r-dh][c])
              area = (dh+1)*minw
              if area > area_max[0]:
              area_max = (area, [(r-dh, c-minw+1, r, c)])

              print('area', area_max[0])
              for t in area_max[1]:
              print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))


              Output:



              area 12
              Cell 1:(2, 1) and Cell 2:(4, 4)





              share|improve this answer














              Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:



              #!/usr/bin/env python3

              import numpy

              s = '''0 0 0 0 1 0
              0 0 1 0 0 1
              0 0 0 0 0 0
              1 0 0 0 0 0
              0 0 0 0 0 1
              0 0 1 0 0 0'''

              nrows = 6
              ncols = 6
              skip = 1
              area_max = (0, )

              a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
              w = numpy.zeros(dtype=int, shape=a.shape)
              h = numpy.zeros(dtype=int, shape=a.shape)
              for r in range(nrows):
              for c in range(ncols):
              if a[r][c] == skip:
              continue
              if r == 0:
              h[r][c] = 1
              else:
              h[r][c] = h[r-1][c]+1
              if c == 0:
              w[r][c] = 1
              else:
              w[r][c] = w[r][c-1]+1
              minw = w[r][c]
              for dh in range(h[r][c]):
              minw = min(minw, w[r-dh][c])
              area = (dh+1)*minw
              if area > area_max[0]:
              area_max = (area, [(r-dh, c-minw+1, r, c)])

              print('area', area_max[0])
              for t in area_max[1]:
              print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))


              Output:



              area 12
              Cell 1:(2, 1) and Cell 2:(4, 4)






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 20 at 22:39









              Eric

              65.9k30168275




              65.9k30168275










              answered May 24 '15 at 0:28









              tommy.carstensen

              3,69253367




              3,69253367























                  3














                  Here is J.F. Sebastians method translated into C#:



                  private Vector2 MaxRectSize(int histogram) {
                  Vector2 maxSize = Vector2.zero;
                  int maxArea = 0;
                  Stack<Vector2> stack = new Stack<Vector2>();

                  int x = 0;
                  for (x = 0; x < histogram.Length; x++) {
                  int start = x;
                  int height = histogram[x];
                  while (true) {
                  if (stack.Count == 0 || height > stack.Peek().y) {
                  stack.Push(new Vector2(start, height));

                  } else if(height < stack.Peek().y) {
                  int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
                  if(tempArea > maxArea) {
                  maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
                  maxArea = tempArea;
                  }

                  Vector2 popped = stack.Pop();
                  start = (int)popped.x;
                  continue;
                  }

                  break;
                  }
                  }

                  foreach (Vector2 data in stack) {
                  int tempArea = (int)(data.y * (x - data.x));
                  if(tempArea > maxArea) {
                  maxSize = new Vector2(data.y, (x - data.x));
                  maxArea = tempArea;
                  }
                  }

                  return maxSize;
                  }

                  public Vector2 GetMaximumFreeSpace() {
                  // STEP 1:
                  // build a seed histogram using the first row of grid points
                  // example: [true, true, false, true] = [1,1,0,1]
                  int hist = new int[gridSizeY];
                  for (int y = 0; y < gridSizeY; y++) {
                  if(!invalidPoints[0, y]) {
                  hist[y] = 1;
                  }
                  }

                  // STEP 2:
                  // get a starting max area from the seed histogram we created above.
                  // using the example from above, this value would be [1, 1], as the only valid area is a single point.
                  // another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
                  // Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
                  // a single row of data.
                  Vector2 maxSize = MaxRectSize(hist);
                  int maxArea = (int)(maxSize.x * maxSize.y);

                  // STEP 3:
                  // build histograms for each additional row, re-testing for new possible max rectangluar areas
                  for (int x = 1; x < gridSizeX; x++) {
                  // build a new histogram for this row. the values of this row are
                  // 0 if the current grid point is occupied; otherwise, it is 1 + the value
                  // of the previously found historgram value for the previous position.
                  // What this does is effectly keep track of the height of continous avilable spaces.
                  // EXAMPLE:
                  // Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
                  // INPUT: OUTPUT:
                  // 1.) [0,0,1,0] = [1,1,0,1]
                  // 2.) [0,0,1,0] = [2,2,0,2]
                  // 3.) [1,1,0,1] = [0,0,1,0]
                  //
                  // As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
                  // free space.
                  for (int y = 0; y < gridSizeY; y++) {
                  if(!invalidPoints[x, y]) {
                  hist[y] = 1 + hist[y];
                  } else {
                  hist[y] = 0;
                  }
                  }

                  // find the maximum size of the current histogram. If it happens to be larger
                  // that the currently recorded max size, then it is the new max size.
                  Vector2 maxSizeTemp = MaxRectSize(hist);
                  int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
                  if (tempArea > maxArea) {
                  maxSize = maxSizeTemp;
                  maxArea = tempArea;
                  }
                  }

                  // at this point, we know the max size
                  return maxSize;
                  }


                  A few things to note about this:




                  1. This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.

                  2. invalidPoints is an array of bool, where true means the grid point is "in use", and false means it is not.






                  share|improve this answer


























                    3














                    Here is J.F. Sebastians method translated into C#:



                    private Vector2 MaxRectSize(int histogram) {
                    Vector2 maxSize = Vector2.zero;
                    int maxArea = 0;
                    Stack<Vector2> stack = new Stack<Vector2>();

                    int x = 0;
                    for (x = 0; x < histogram.Length; x++) {
                    int start = x;
                    int height = histogram[x];
                    while (true) {
                    if (stack.Count == 0 || height > stack.Peek().y) {
                    stack.Push(new Vector2(start, height));

                    } else if(height < stack.Peek().y) {
                    int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
                    if(tempArea > maxArea) {
                    maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
                    maxArea = tempArea;
                    }

                    Vector2 popped = stack.Pop();
                    start = (int)popped.x;
                    continue;
                    }

                    break;
                    }
                    }

                    foreach (Vector2 data in stack) {
                    int tempArea = (int)(data.y * (x - data.x));
                    if(tempArea > maxArea) {
                    maxSize = new Vector2(data.y, (x - data.x));
                    maxArea = tempArea;
                    }
                    }

                    return maxSize;
                    }

                    public Vector2 GetMaximumFreeSpace() {
                    // STEP 1:
                    // build a seed histogram using the first row of grid points
                    // example: [true, true, false, true] = [1,1,0,1]
                    int hist = new int[gridSizeY];
                    for (int y = 0; y < gridSizeY; y++) {
                    if(!invalidPoints[0, y]) {
                    hist[y] = 1;
                    }
                    }

                    // STEP 2:
                    // get a starting max area from the seed histogram we created above.
                    // using the example from above, this value would be [1, 1], as the only valid area is a single point.
                    // another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
                    // Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
                    // a single row of data.
                    Vector2 maxSize = MaxRectSize(hist);
                    int maxArea = (int)(maxSize.x * maxSize.y);

                    // STEP 3:
                    // build histograms for each additional row, re-testing for new possible max rectangluar areas
                    for (int x = 1; x < gridSizeX; x++) {
                    // build a new histogram for this row. the values of this row are
                    // 0 if the current grid point is occupied; otherwise, it is 1 + the value
                    // of the previously found historgram value for the previous position.
                    // What this does is effectly keep track of the height of continous avilable spaces.
                    // EXAMPLE:
                    // Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
                    // INPUT: OUTPUT:
                    // 1.) [0,0,1,0] = [1,1,0,1]
                    // 2.) [0,0,1,0] = [2,2,0,2]
                    // 3.) [1,1,0,1] = [0,0,1,0]
                    //
                    // As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
                    // free space.
                    for (int y = 0; y < gridSizeY; y++) {
                    if(!invalidPoints[x, y]) {
                    hist[y] = 1 + hist[y];
                    } else {
                    hist[y] = 0;
                    }
                    }

                    // find the maximum size of the current histogram. If it happens to be larger
                    // that the currently recorded max size, then it is the new max size.
                    Vector2 maxSizeTemp = MaxRectSize(hist);
                    int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
                    if (tempArea > maxArea) {
                    maxSize = maxSizeTemp;
                    maxArea = tempArea;
                    }
                    }

                    // at this point, we know the max size
                    return maxSize;
                    }


                    A few things to note about this:




                    1. This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.

                    2. invalidPoints is an array of bool, where true means the grid point is "in use", and false means it is not.






                    share|improve this answer
























                      3












                      3








                      3






                      Here is J.F. Sebastians method translated into C#:



                      private Vector2 MaxRectSize(int histogram) {
                      Vector2 maxSize = Vector2.zero;
                      int maxArea = 0;
                      Stack<Vector2> stack = new Stack<Vector2>();

                      int x = 0;
                      for (x = 0; x < histogram.Length; x++) {
                      int start = x;
                      int height = histogram[x];
                      while (true) {
                      if (stack.Count == 0 || height > stack.Peek().y) {
                      stack.Push(new Vector2(start, height));

                      } else if(height < stack.Peek().y) {
                      int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
                      if(tempArea > maxArea) {
                      maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
                      maxArea = tempArea;
                      }

                      Vector2 popped = stack.Pop();
                      start = (int)popped.x;
                      continue;
                      }

                      break;
                      }
                      }

                      foreach (Vector2 data in stack) {
                      int tempArea = (int)(data.y * (x - data.x));
                      if(tempArea > maxArea) {
                      maxSize = new Vector2(data.y, (x - data.x));
                      maxArea = tempArea;
                      }
                      }

                      return maxSize;
                      }

                      public Vector2 GetMaximumFreeSpace() {
                      // STEP 1:
                      // build a seed histogram using the first row of grid points
                      // example: [true, true, false, true] = [1,1,0,1]
                      int hist = new int[gridSizeY];
                      for (int y = 0; y < gridSizeY; y++) {
                      if(!invalidPoints[0, y]) {
                      hist[y] = 1;
                      }
                      }

                      // STEP 2:
                      // get a starting max area from the seed histogram we created above.
                      // using the example from above, this value would be [1, 1], as the only valid area is a single point.
                      // another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
                      // Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
                      // a single row of data.
                      Vector2 maxSize = MaxRectSize(hist);
                      int maxArea = (int)(maxSize.x * maxSize.y);

                      // STEP 3:
                      // build histograms for each additional row, re-testing for new possible max rectangluar areas
                      for (int x = 1; x < gridSizeX; x++) {
                      // build a new histogram for this row. the values of this row are
                      // 0 if the current grid point is occupied; otherwise, it is 1 + the value
                      // of the previously found historgram value for the previous position.
                      // What this does is effectly keep track of the height of continous avilable spaces.
                      // EXAMPLE:
                      // Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
                      // INPUT: OUTPUT:
                      // 1.) [0,0,1,0] = [1,1,0,1]
                      // 2.) [0,0,1,0] = [2,2,0,2]
                      // 3.) [1,1,0,1] = [0,0,1,0]
                      //
                      // As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
                      // free space.
                      for (int y = 0; y < gridSizeY; y++) {
                      if(!invalidPoints[x, y]) {
                      hist[y] = 1 + hist[y];
                      } else {
                      hist[y] = 0;
                      }
                      }

                      // find the maximum size of the current histogram. If it happens to be larger
                      // that the currently recorded max size, then it is the new max size.
                      Vector2 maxSizeTemp = MaxRectSize(hist);
                      int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
                      if (tempArea > maxArea) {
                      maxSize = maxSizeTemp;
                      maxArea = tempArea;
                      }
                      }

                      // at this point, we know the max size
                      return maxSize;
                      }


                      A few things to note about this:




                      1. This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.

                      2. invalidPoints is an array of bool, where true means the grid point is "in use", and false means it is not.






                      share|improve this answer












                      Here is J.F. Sebastians method translated into C#:



                      private Vector2 MaxRectSize(int histogram) {
                      Vector2 maxSize = Vector2.zero;
                      int maxArea = 0;
                      Stack<Vector2> stack = new Stack<Vector2>();

                      int x = 0;
                      for (x = 0; x < histogram.Length; x++) {
                      int start = x;
                      int height = histogram[x];
                      while (true) {
                      if (stack.Count == 0 || height > stack.Peek().y) {
                      stack.Push(new Vector2(start, height));

                      } else if(height < stack.Peek().y) {
                      int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
                      if(tempArea > maxArea) {
                      maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
                      maxArea = tempArea;
                      }

                      Vector2 popped = stack.Pop();
                      start = (int)popped.x;
                      continue;
                      }

                      break;
                      }
                      }

                      foreach (Vector2 data in stack) {
                      int tempArea = (int)(data.y * (x - data.x));
                      if(tempArea > maxArea) {
                      maxSize = new Vector2(data.y, (x - data.x));
                      maxArea = tempArea;
                      }
                      }

                      return maxSize;
                      }

                      public Vector2 GetMaximumFreeSpace() {
                      // STEP 1:
                      // build a seed histogram using the first row of grid points
                      // example: [true, true, false, true] = [1,1,0,1]
                      int hist = new int[gridSizeY];
                      for (int y = 0; y < gridSizeY; y++) {
                      if(!invalidPoints[0, y]) {
                      hist[y] = 1;
                      }
                      }

                      // STEP 2:
                      // get a starting max area from the seed histogram we created above.
                      // using the example from above, this value would be [1, 1], as the only valid area is a single point.
                      // another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
                      // Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
                      // a single row of data.
                      Vector2 maxSize = MaxRectSize(hist);
                      int maxArea = (int)(maxSize.x * maxSize.y);

                      // STEP 3:
                      // build histograms for each additional row, re-testing for new possible max rectangluar areas
                      for (int x = 1; x < gridSizeX; x++) {
                      // build a new histogram for this row. the values of this row are
                      // 0 if the current grid point is occupied; otherwise, it is 1 + the value
                      // of the previously found historgram value for the previous position.
                      // What this does is effectly keep track of the height of continous avilable spaces.
                      // EXAMPLE:
                      // Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
                      // INPUT: OUTPUT:
                      // 1.) [0,0,1,0] = [1,1,0,1]
                      // 2.) [0,0,1,0] = [2,2,0,2]
                      // 3.) [1,1,0,1] = [0,0,1,0]
                      //
                      // As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
                      // free space.
                      for (int y = 0; y < gridSizeY; y++) {
                      if(!invalidPoints[x, y]) {
                      hist[y] = 1 + hist[y];
                      } else {
                      hist[y] = 0;
                      }
                      }

                      // find the maximum size of the current histogram. If it happens to be larger
                      // that the currently recorded max size, then it is the new max size.
                      Vector2 maxSizeTemp = MaxRectSize(hist);
                      int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
                      if (tempArea > maxArea) {
                      maxSize = maxSizeTemp;
                      maxArea = tempArea;
                      }
                      }

                      // at this point, we know the max size
                      return maxSize;
                      }


                      A few things to note about this:




                      1. This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.

                      2. invalidPoints is an array of bool, where true means the grid point is "in use", and false means it is not.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Apr 8 '15 at 22:36









                      dmarra

                      446317




                      446317























                          3














                          Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)



                          public int maximalRectangle(char matrix) {
                          int m = matrix.length;
                          if (m == 0)
                          return 0;
                          int n = matrix[0].length;
                          int maxArea = 0;
                          int aux = new int[n];
                          for (int i = 0; i < n; i++) {
                          aux[i] = 0;
                          }
                          for (int i = 0; i < m; i++) {
                          for (int j = 0; j < n; j++) {
                          aux[j] = matrix[i][j] - '0' + aux[j];
                          maxArea = Math.max(maxArea, maxAreaHist(aux));
                          }
                          }
                          return maxArea;
                          }

                          public int maxAreaHist(int heights) {
                          int n = heights.length;
                          Stack<Integer> stack = new Stack<Integer>();
                          stack.push(0);
                          int maxRect = heights[0];
                          int top = 0;
                          int leftSideArea = 0;
                          int rightSideArea = heights[0];
                          for (int i = 1; i < n; i++) {
                          if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
                          stack.push(i);
                          } else {
                          while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (i - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          stack.push(i);
                          }
                          }
                          while (!stack.isEmpty()) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (n - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          return maxRect;
                          }


                          But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?






                          share|improve this answer





















                          • Input at leet code has 200 rows and 200 columns
                            – Astha Gupta
                            May 14 '16 at 8:13










                          • Simple and easy to understand.. Thank you!
                            – Swadhikar C
                            Jul 9 '16 at 4:02
















                          3














                          Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)



                          public int maximalRectangle(char matrix) {
                          int m = matrix.length;
                          if (m == 0)
                          return 0;
                          int n = matrix[0].length;
                          int maxArea = 0;
                          int aux = new int[n];
                          for (int i = 0; i < n; i++) {
                          aux[i] = 0;
                          }
                          for (int i = 0; i < m; i++) {
                          for (int j = 0; j < n; j++) {
                          aux[j] = matrix[i][j] - '0' + aux[j];
                          maxArea = Math.max(maxArea, maxAreaHist(aux));
                          }
                          }
                          return maxArea;
                          }

                          public int maxAreaHist(int heights) {
                          int n = heights.length;
                          Stack<Integer> stack = new Stack<Integer>();
                          stack.push(0);
                          int maxRect = heights[0];
                          int top = 0;
                          int leftSideArea = 0;
                          int rightSideArea = heights[0];
                          for (int i = 1; i < n; i++) {
                          if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
                          stack.push(i);
                          } else {
                          while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (i - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          stack.push(i);
                          }
                          }
                          while (!stack.isEmpty()) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (n - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          return maxRect;
                          }


                          But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?






                          share|improve this answer





















                          • Input at leet code has 200 rows and 200 columns
                            – Astha Gupta
                            May 14 '16 at 8:13










                          • Simple and easy to understand.. Thank you!
                            – Swadhikar C
                            Jul 9 '16 at 4:02














                          3












                          3








                          3






                          Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)



                          public int maximalRectangle(char matrix) {
                          int m = matrix.length;
                          if (m == 0)
                          return 0;
                          int n = matrix[0].length;
                          int maxArea = 0;
                          int aux = new int[n];
                          for (int i = 0; i < n; i++) {
                          aux[i] = 0;
                          }
                          for (int i = 0; i < m; i++) {
                          for (int j = 0; j < n; j++) {
                          aux[j] = matrix[i][j] - '0' + aux[j];
                          maxArea = Math.max(maxArea, maxAreaHist(aux));
                          }
                          }
                          return maxArea;
                          }

                          public int maxAreaHist(int heights) {
                          int n = heights.length;
                          Stack<Integer> stack = new Stack<Integer>();
                          stack.push(0);
                          int maxRect = heights[0];
                          int top = 0;
                          int leftSideArea = 0;
                          int rightSideArea = heights[0];
                          for (int i = 1; i < n; i++) {
                          if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
                          stack.push(i);
                          } else {
                          while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (i - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          stack.push(i);
                          }
                          }
                          while (!stack.isEmpty()) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (n - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          return maxRect;
                          }


                          But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?






                          share|improve this answer












                          Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)



                          public int maximalRectangle(char matrix) {
                          int m = matrix.length;
                          if (m == 0)
                          return 0;
                          int n = matrix[0].length;
                          int maxArea = 0;
                          int aux = new int[n];
                          for (int i = 0; i < n; i++) {
                          aux[i] = 0;
                          }
                          for (int i = 0; i < m; i++) {
                          for (int j = 0; j < n; j++) {
                          aux[j] = matrix[i][j] - '0' + aux[j];
                          maxArea = Math.max(maxArea, maxAreaHist(aux));
                          }
                          }
                          return maxArea;
                          }

                          public int maxAreaHist(int heights) {
                          int n = heights.length;
                          Stack<Integer> stack = new Stack<Integer>();
                          stack.push(0);
                          int maxRect = heights[0];
                          int top = 0;
                          int leftSideArea = 0;
                          int rightSideArea = heights[0];
                          for (int i = 1; i < n; i++) {
                          if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
                          stack.push(i);
                          } else {
                          while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (i - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          stack.push(i);
                          }
                          }
                          while (!stack.isEmpty()) {
                          top = stack.pop();
                          rightSideArea = heights[top] * (n - top);
                          leftSideArea = 0;
                          if (!stack.isEmpty()) {
                          leftSideArea = heights[top] * (top - stack.peek() - 1);
                          } else {
                          leftSideArea = heights[top] * top;
                          }
                          maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
                          }
                          return maxRect;
                          }


                          But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered May 14 '16 at 8:10









                          Astha Gupta

                          655719




                          655719












                          • Input at leet code has 200 rows and 200 columns
                            – Astha Gupta
                            May 14 '16 at 8:13










                          • Simple and easy to understand.. Thank you!
                            – Swadhikar C
                            Jul 9 '16 at 4:02


















                          • Input at leet code has 200 rows and 200 columns
                            – Astha Gupta
                            May 14 '16 at 8:13










                          • Simple and easy to understand.. Thank you!
                            – Swadhikar C
                            Jul 9 '16 at 4:02
















                          Input at leet code has 200 rows and 200 columns
                          – Astha Gupta
                          May 14 '16 at 8:13




                          Input at leet code has 200 rows and 200 columns
                          – Astha Gupta
                          May 14 '16 at 8:13












                          Simple and easy to understand.. Thank you!
                          – Swadhikar C
                          Jul 9 '16 at 4:02




                          Simple and easy to understand.. Thank you!
                          – Swadhikar C
                          Jul 9 '16 at 4:02











                          2














                          I propose a O(nxn) method.



                          First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.



                          A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).



                          Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).



                          Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).



                          In practice, this method is very fast, and is used for realtime video stream analysis.






                          share|improve this answer




























                            2














                            I propose a O(nxn) method.



                            First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.



                            A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).



                            Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).



                            Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).



                            In practice, this method is very fast, and is used for realtime video stream analysis.






                            share|improve this answer


























                              2












                              2








                              2






                              I propose a O(nxn) method.



                              First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.



                              A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).



                              Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).



                              Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).



                              In practice, this method is very fast, and is used for realtime video stream analysis.






                              share|improve this answer














                              I propose a O(nxn) method.



                              First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.



                              A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).



                              Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).



                              Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).



                              In practice, this method is very fast, and is used for realtime video stream analysis.







                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Jul 7 '13 at 21:51









                              Pierre Fourgeaud

                              12.5k12553




                              12.5k12553










                              answered Jul 7 '13 at 21:26









                              S. Piérard

                              864




                              864























                                  0














                                  Here is a version of jfs' solution, which also delivers the position of the largest rectangle:



                                  from collections import namedtuple
                                  from operator import mul

                                  Info = namedtuple('Info', 'start height')

                                  def max_rect(mat, value=0):
                                  """returns (height, width, left_column, bottom_row) of the largest rectangle
                                  containing all `value`'s.

                                  Example:
                                  [[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
                                  [0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
                                  [1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
                                  [0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
                                  [0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
                                  [4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
                                  [3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
                                  [0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
                                  [0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
                                  gives: (3, 4, 6, 5)
                                  """
                                  it = iter(mat)
                                  hist = [(el==value) for el in next(it, )]
                                  max_rect = max_rectangle_size(hist) + (0,)
                                  for irow,row in enumerate(it):
                                  hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
                                  max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
                                  # irow+1, because we already used one row for initializing max_rect
                                  return max_rect

                                  def max_rectangle_size(histogram):
                                  stack =
                                  top = lambda: stack[-1]
                                  max_size = (0, 0, 0) # height, width and start position of the largest rectangle
                                  pos = 0 # current position in the histogram
                                  for pos, height in enumerate(histogram):
                                  start = pos # position where rectangle starts
                                  while True:
                                  if not stack or height > top().height:
                                  stack.append(Info(start, height)) # push
                                  elif stack and height < top().height:
                                  max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
                                  start, _ = stack.pop()
                                  continue
                                  break # height == top().height goes here

                                  pos += 1
                                  for start, height in stack:
                                  max_size = max(max_size, (height, (pos - start), start), key=area)

                                  return max_size

                                  def area(size):
                                  return size[0] * size[1]





                                  share|improve this answer




























                                    0














                                    Here is a version of jfs' solution, which also delivers the position of the largest rectangle:



                                    from collections import namedtuple
                                    from operator import mul

                                    Info = namedtuple('Info', 'start height')

                                    def max_rect(mat, value=0):
                                    """returns (height, width, left_column, bottom_row) of the largest rectangle
                                    containing all `value`'s.

                                    Example:
                                    [[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
                                    [0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
                                    [1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
                                    [0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
                                    [0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
                                    [4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
                                    [3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
                                    [0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
                                    [0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
                                    gives: (3, 4, 6, 5)
                                    """
                                    it = iter(mat)
                                    hist = [(el==value) for el in next(it, )]
                                    max_rect = max_rectangle_size(hist) + (0,)
                                    for irow,row in enumerate(it):
                                    hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
                                    max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
                                    # irow+1, because we already used one row for initializing max_rect
                                    return max_rect

                                    def max_rectangle_size(histogram):
                                    stack =
                                    top = lambda: stack[-1]
                                    max_size = (0, 0, 0) # height, width and start position of the largest rectangle
                                    pos = 0 # current position in the histogram
                                    for pos, height in enumerate(histogram):
                                    start = pos # position where rectangle starts
                                    while True:
                                    if not stack or height > top().height:
                                    stack.append(Info(start, height)) # push
                                    elif stack and height < top().height:
                                    max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
                                    start, _ = stack.pop()
                                    continue
                                    break # height == top().height goes here

                                    pos += 1
                                    for start, height in stack:
                                    max_size = max(max_size, (height, (pos - start), start), key=area)

                                    return max_size

                                    def area(size):
                                    return size[0] * size[1]





                                    share|improve this answer


























                                      0












                                      0








                                      0






                                      Here is a version of jfs' solution, which also delivers the position of the largest rectangle:



                                      from collections import namedtuple
                                      from operator import mul

                                      Info = namedtuple('Info', 'start height')

                                      def max_rect(mat, value=0):
                                      """returns (height, width, left_column, bottom_row) of the largest rectangle
                                      containing all `value`'s.

                                      Example:
                                      [[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
                                      [0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
                                      [1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
                                      [0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
                                      [0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
                                      [4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
                                      [3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
                                      [0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
                                      [0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
                                      gives: (3, 4, 6, 5)
                                      """
                                      it = iter(mat)
                                      hist = [(el==value) for el in next(it, )]
                                      max_rect = max_rectangle_size(hist) + (0,)
                                      for irow,row in enumerate(it):
                                      hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
                                      max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
                                      # irow+1, because we already used one row for initializing max_rect
                                      return max_rect

                                      def max_rectangle_size(histogram):
                                      stack =
                                      top = lambda: stack[-1]
                                      max_size = (0, 0, 0) # height, width and start position of the largest rectangle
                                      pos = 0 # current position in the histogram
                                      for pos, height in enumerate(histogram):
                                      start = pos # position where rectangle starts
                                      while True:
                                      if not stack or height > top().height:
                                      stack.append(Info(start, height)) # push
                                      elif stack and height < top().height:
                                      max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
                                      start, _ = stack.pop()
                                      continue
                                      break # height == top().height goes here

                                      pos += 1
                                      for start, height in stack:
                                      max_size = max(max_size, (height, (pos - start), start), key=area)

                                      return max_size

                                      def area(size):
                                      return size[0] * size[1]





                                      share|improve this answer














                                      Here is a version of jfs' solution, which also delivers the position of the largest rectangle:



                                      from collections import namedtuple
                                      from operator import mul

                                      Info = namedtuple('Info', 'start height')

                                      def max_rect(mat, value=0):
                                      """returns (height, width, left_column, bottom_row) of the largest rectangle
                                      containing all `value`'s.

                                      Example:
                                      [[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
                                      [0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
                                      [1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
                                      [0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
                                      [0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
                                      [4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
                                      [3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
                                      [0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
                                      [0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
                                      gives: (3, 4, 6, 5)
                                      """
                                      it = iter(mat)
                                      hist = [(el==value) for el in next(it, )]
                                      max_rect = max_rectangle_size(hist) + (0,)
                                      for irow,row in enumerate(it):
                                      hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
                                      max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
                                      # irow+1, because we already used one row for initializing max_rect
                                      return max_rect

                                      def max_rectangle_size(histogram):
                                      stack =
                                      top = lambda: stack[-1]
                                      max_size = (0, 0, 0) # height, width and start position of the largest rectangle
                                      pos = 0 # current position in the histogram
                                      for pos, height in enumerate(histogram):
                                      start = pos # position where rectangle starts
                                      while True:
                                      if not stack or height > top().height:
                                      stack.append(Info(start, height)) # push
                                      elif stack and height < top().height:
                                      max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
                                      start, _ = stack.pop()
                                      continue
                                      break # height == top().height goes here

                                      pos += 1
                                      for start, height in stack:
                                      max_size = max(max_size, (height, (pos - start), start), key=area)

                                      return max_size

                                      def area(size):
                                      return size[0] * size[1]






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Oct 5 at 11:52

























                                      answered Oct 3 at 9:38









                                      MiB_Coder

                                      129210




                                      129210






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.





                                          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                          Please pay close attention to the following guidance:


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2478447%2ffind-largest-rectangle-containing-only-zeros-in-an-n%25c3%2597n-binary-matrix%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          404 Error Contact Form 7 ajax form submitting

                                          How to know if a Active Directory user can login interactively

                                          Refactoring coordinates for Minecraft Pi buildings written in Python