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

前端 未结 8 2335
伪装坚强ぢ
伪装坚强ぢ 2020-11-22 06:25

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          


        
8条回答
  •  迷失自我
    2020-11-22 06:41

    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

提交回复
热议问题