Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

302. Smallest Rectangle Enclosing Black Pixels - Leetcode Solution

Problem Description

You are given a 2D binary image represented as a list of strings, where each string is a row and each character is either '0' (white pixel) or '1' (black pixel). You are also given the location (x, y) of one of the black pixels.
Your task is to find the area of the smallest (axis-aligned) rectangle that encloses all black pixels ('1') in the image. The rectangle's sides must be parallel to the image axes.

  • There is exactly one connected black region (all black pixels are connected horizontally or vertically).
  • x and y are guaranteed to be within the bounds of the image and point to a black pixel.
  • You may not reuse pixels outside the black region.

Thought Process

The naive approach is to scan the entire image and record the minimum and maximum row and column indices where a black pixel appears. This would let us compute the rectangle directly.
However, since the black region is connected and we’re given a starting black pixel, we can optimize by only searching the connected region using BFS or DFS. But, if the black area is large or scattered, scanning the whole image may be more straightforward.
To further optimize, we can use binary search to find the leftmost, rightmost, topmost, and bottommost black pixels, reducing the number of rows and columns we need to check.
The key insight is that the minimum rectangle is defined by the smallest and largest row and column indices containing a black pixel.

Solution Approach

  • Step 1: Initialize four variables to track the boundaries of the rectangle: minRow, maxRow, minCol, and maxCol.
  • Step 2: Traverse the image. For each black pixel ('1'), update the boundary variables:
    • If the current row is less than minRow, update minRow.
    • If the current row is greater than maxRow, update maxRow.
    • Similarly for columns with minCol and maxCol.
  • Step 3: After traversing the image, the rectangle's area is (maxRow - minRow + 1) * (maxCol - minCol + 1).
  • Optimization: If the image is very large and the black region is small, use BFS/DFS from the starting pixel to only visit black pixels in the connected region, updating the boundaries as you go.
  • Further Optimization: Use binary search to find the first and last rows/columns containing a black pixel, reducing the number of checks needed, especially if the black region is dense.

For most cases, the simple scan is efficient and easy to understand.

Example Walkthrough

Consider the following image:

    image = [
      "0010",
      "0110",
      "0100"
    ]
    x = 0, y = 2
  
  • Row 0: Only column 2 has a black pixel.
  • Row 1: Columns 1 and 2 have black pixels.
  • Row 2: Column 1 has a black pixel.

The boundaries are:

  • minRow = 0 (topmost black pixel)
  • maxRow = 2 (bottommost black pixel)
  • minCol = 1 (leftmost black pixel)
  • maxCol = 2 (rightmost black pixel)

The rectangle is from (0,1) to (2,2), so the area is (2-0+1) * (2-1+1) = 3 * 2 = 6.

Code Implementation

class Solution:
    def minArea(self, image, x, y):
        m, n = len(image), len(image[0])
        minRow, maxRow = m, 0
        minCol, maxCol = n, 0
        for i in range(m):
            for j in range(n):
                if image[i][j] == '1':
                    minRow = min(minRow, i)
                    maxRow = max(maxRow, i)
                    minCol = min(minCol, j)
                    maxCol = max(maxCol, j)
        return (maxRow - minRow + 1) * (maxCol - minCol + 1)
      
class Solution {
public:
    int minArea(vector<string>& image, int x, int y) {
        int m = image.size(), n = image[0].size();
        int minRow = m, maxRow = 0, minCol = n, maxCol = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (image[i][j] == '1') {
                    minRow = min(minRow, i);
                    maxRow = max(maxRow, i);
                    minCol = min(minCol, j);
                    maxCol = max(maxCol, j);
                }
            }
        }
        return (maxRow - minRow + 1) * (maxCol - minCol + 1);
    }
};
      
class Solution {
    public int minArea(char[][] image, int x, int y) {
        int m = image.length, n = image[0].length;
        int minRow = m, maxRow = 0, minCol = n, maxCol = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (image[i][j] == '1') {
                    minRow = Math.min(minRow, i);
                    maxRow = Math.max(maxRow, i);
                    minCol = Math.min(minCol, j);
                    maxCol = Math.max(maxCol, j);
                }
            }
        }
        return (maxRow - minRow + 1) * (maxCol - minCol + 1);
    }
}
      
var minArea = function(image, x, y) {
    let m = image.length, n = image[0].length;
    let minRow = m, maxRow = 0, minCol = n, maxCol = 0;
    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            if (image[i][j] === '1') {
                minRow = Math.min(minRow, i);
                maxRow = Math.max(maxRow, i);
                minCol = Math.min(minCol, j);
                maxCol = Math.max(maxCol, j);
            }
        }
    }
    return (maxRow - minRow + 1) * (maxCol - minCol + 1);
};
      

Time and Space Complexity

  • Brute-Force Approach: We scan every pixel in the image, so the time complexity is O(m * n), where m is the number of rows and n is the number of columns. Space complexity is O(1) since we only use a few variables for boundaries.
  • Optimized BFS/DFS Approach: If we use BFS or DFS, the time complexity is O(k), where k is the number of black pixels (since we only visit connected black pixels). Space complexity is O(k) for the queue or stack.
  • Binary Search Approach: Each binary search over rows or columns takes O(log m * n) time per direction, but since we need to check each row/column in the search, the overall complexity is still roughly O(m * n) in the worst case.

Summary

The problem boils down to finding the minimum and maximum row and column indices of black pixels. By scanning the image and updating boundary variables, we can compute the area of the smallest rectangle that encloses all black pixels. This approach is simple, effective, and optimal for most practical input sizes. If the black region is much smaller than the image, BFS/DFS can further optimize the search. The elegance of the solution lies in its directness: just track the boundaries as you go!