{x}
blog image

Smallest Rectangle Enclosing Black Pixels

Solution Explanation:

This problem asks to find the smallest rectangle enclosing all black pixels in a binary matrix. The constraint of less than O(mn) runtime complexity prevents us from iterating through the entire matrix. Instead, we use binary search to efficiently find the boundaries of the black pixel region.

The solution leverages the fact that the black pixels are connected. This allows us to start from a known black pixel (x, y) and use binary search to find the topmost, bottommost, leftmost, and rightmost black pixels.

Approach:

  1. Binary Search for Top and Bottom: We perform two binary searches on the rows.

    • The first search finds the topmost row (u) containing at least one black pixel. It starts from row 0 and searches upwards.
    • The second search finds the bottommost row (d) containing at least one black pixel. It starts from row x and searches downwards.
  2. Binary Search for Left and Right: Similarly, we perform two binary searches on the columns.

    • The first search finds the leftmost column (l) containing at least one black pixel. It starts from column 0 and searches leftwards.
    • The second search finds the rightmost column (r) containing at least one black pixel. It starts from column y and searches rightwards.
  3. Calculate Area: Once we've found the boundaries (u, d, l, r), the area of the smallest enclosing rectangle is simply (d - u + 1) * (r - l + 1).

Time Complexity Analysis:

The dominant operations are the four binary searches. Each binary search takes O(m) or O(n) time in the worst case (where m and n are the dimensions of the matrix). Therefore, the overall time complexity is O(m + n), which is significantly less than O(mn).

Space Complexity Analysis:

The space complexity is O(1) because we only use a constant number of variables to store the boundaries.

Code Explanation (Python3):

class Solution:
    def minArea(self, image: List[List[str]], x: int, y: int) -> int:
        m, n = len(image), len(image[0])
        
        # Binary search for topmost row (u)
        left, right = 0, x
        while left < right:
            mid = (left + right) // 2  #Integer division
            c = 0
            while c < n and image[mid][c] == '0':
                c += 1
            if c < n:  #Found a black pixel in this row
                right = mid
            else:
                left = mid + 1
        u = left
 
        # Binary search for bottommost row (d)
        left, right = x, m - 1
        while left < right:
            mid = (left + right + 1) // 2 # Ceil to ensure we include the row
            c = 0
            while c < n and image[mid][c] == '0':
                c += 1
            if c < n: # Found a black pixel in this row
                left = mid
            else:
                right = mid - 1
        d = left
 
        #Binary search for leftmost column (l)
        left, right = 0, y
        while left < right:
            mid = (left + right) // 2
            r = 0
            while r < m and image[r][mid] == '0':
                r += 1
            if r < m: # Found a black pixel in this column
                right = mid
            else:
                left = mid + 1
        l = left
        
        #Binary search for rightmost column (r)
        left, right = y, n -1
        while left < right:
            mid = (left + right + 1) // 2 # Ceil to ensure inclusion
            r = 0
            while r < m and image[r][mid] == '0':
                r += 1
            if r < m: #Found black pixel in this column
                left = mid
            else:
                right = mid - 1
        r = left
        
        return (d - u + 1) * (r - l + 1)
 

The code in other languages (Java, C++, Go) follows the same logic and uses binary search in a similar manner. The only differences are syntax and standard library functions.