|
| 1 | +--- |
| 2 | +id: smallest-rectangle-enclosing-black-pixels |
| 3 | +title: Smallest Rectangle Enclosing Black Pixels |
| 4 | +sidebar_label: 0302-Smallest-Rectangle-Enclosing-Black-Pixels |
| 5 | +tags: [Binary Search, Matrix, Array, Hard] |
| 6 | +description: Given an image represented by a binary matrix where 0 is a white pixel and 1 is a black pixel, return the area of the smallest rectangle that encloses all black pixels. The black pixels are connected, and the rectangle must be axis-aligned. |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## Problem Statement |
| 11 | + |
| 12 | +You are given an `m x n` binary matrix `image` where `0` represents a white pixel and `1` represents a black pixel. The black pixels are connected, i.e., there is only one black region. Pixels are connected horizontally and vertically. |
| 13 | + |
| 14 | +Given the location `(x, y)` of one of the black pixels, return the area of the smallest (axis-aligned) rectangle that encloses all black pixels. |
| 15 | + |
| 16 | +**You must write an algorithm with less than O(mn) runtime complexity.** |
| 17 | + |
| 18 | +### Examples |
| 19 | + |
| 20 | +**Example 1:** |
| 21 | + |
| 22 | +```plaintext |
| 23 | +Input: image = [["0","0","1","0"],["0","1","1","0"],["0","1","0","0"]], x = 0, y = 2 |
| 24 | +Output: 6 |
| 25 | +``` |
| 26 | + |
| 27 | +**Example 2:** |
| 28 | + |
| 29 | +```plaintext |
| 30 | +Input: image = [["1"]], x = 0, y = 0 |
| 31 | +Output: 1 |
| 32 | +``` |
| 33 | +### Constraints |
| 34 | +- m == image.length |
| 35 | +- n == image[i].length |
| 36 | +- 1 <= m, n <= 100 |
| 37 | +- image[i][j] is either '0' or '1'. |
| 38 | +- 0 <= x < m |
| 39 | +- 0 <= y < n |
| 40 | +- image[x][y] == '1' |
| 41 | +- The black pixels in the image only form one component. |
| 42 | +- At most 10^4 calls will be made to `add` and `find`. |
| 43 | + |
| 44 | + |
| 45 | +## Solution |
| 46 | + |
| 47 | +### Approach |
| 48 | + |
| 49 | +We use binary search to find the left, right, top, and bottom edges of the rectangle that encloses all the black pixels. |
| 50 | + |
| 51 | +#### Algorithm |
| 52 | + |
| 53 | +`Binary Search` to hold remainder. |
| 54 | + |
| 55 | +- Horizontal Search: Find the top and bottom boundaries of the rectangle by searching for rows that contain black pixels. |
| 56 | +- Vertical Search: Find the left and right boundaries of the rectangle by searching for columns that contain black pixels. |
| 57 | + |
| 58 | +#### Implementation |
| 59 | + |
| 60 | +## (Java) |
| 61 | + |
| 62 | +```Java |
| 63 | +public class Smallest_Rectangle_Enclosing_Black_Pixels { |
| 64 | + |
| 65 | + public class Solution_BinarySearch { |
| 66 | + public int minArea(char[][] image, int x, int y) { |
| 67 | + if (image == null || image.length == 0) { |
| 68 | + return 0; |
| 69 | + } |
| 70 | + |
| 71 | + int m = image.length; |
| 72 | + int n = image[0].length; |
| 73 | + |
| 74 | + int up = binarySearch(image, true, 0, x, 0, n, true); |
| 75 | + int down = binarySearch(image, true, x + 1, m, 0, n, false); |
| 76 | + int left = binarySearch(image, false, 0, y, up, down, true); |
| 77 | + int right = binarySearch(image, false, y + 1, n, up, down, false); |
| 78 | + |
| 79 | + return (right - left) * (down - up); |
| 80 | + } |
| 81 | + |
| 82 | + int binarySearch(char[][] image, boolean isHorizontal, int i, int j, int low, int high, boolean opt) { |
| 83 | + while (i < j) { |
| 84 | + int k = low; |
| 85 | + int mid = (i + j) / 2; |
| 86 | + |
| 87 | + while (k < high && (isHorizontal ? image[mid][k] : image[k][mid]) == '0') { |
| 88 | + ++k; |
| 89 | + } |
| 90 | + |
| 91 | + if (k < high == opt) { |
| 92 | + j = mid; |
| 93 | + } else { |
| 94 | + i = mid + 1; |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + return i; |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + class Solution_BruteForce { |
| 103 | + public int minArea(char[][] image, int x, int y) { |
| 104 | + int rows = image.length, columns = image[0].length; |
| 105 | + int top = x, bottom = x, left = y, right = y; |
| 106 | + int[][] directions = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; |
| 107 | + image[x][y] = '2'; |
| 108 | + Queue<int[]> queue = new LinkedList<>(); |
| 109 | + queue.offer(new int[]{x, y}); |
| 110 | + while (!queue.isEmpty()) { |
| 111 | + int[] cell = queue.poll(); |
| 112 | + int row = cell[0], column = cell[1]; |
| 113 | + for (int[] direction : directions) { |
| 114 | + int newRow = row + direction[0], newColumn = column + direction[1]; |
| 115 | + if (newRow >= 0 && newRow < rows && newColumn >= 0 && newColumn < columns && image[newRow][newColumn] == '1') { |
| 116 | + image[newRow][newColumn] = '2'; |
| 117 | + top = Math.min(top, newRow); |
| 118 | + bottom = Math.max(bottom, newRow); |
| 119 | + left = Math.min(left, newColumn); |
| 120 | + right = Math.max(right, newColumn); |
| 121 | + queue.offer(new int[]{newRow, newColumn}); |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + return (bottom - top + 1) * (right - left + 1); |
| 126 | + } |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +``` |
| 131 | + |
| 132 | +## (C++) |
| 133 | +``` C++ |
| 134 | +C++ |
| 135 | +class TwoSum { |
| 136 | + Map<Integer,Boolean> map; |
| 137 | + List<Integer> list; |
| 138 | + int low = Integer.MAX_VALUE; |
| 139 | + int high = Integer.MIN_VALUE; |
| 140 | + /** Initialize your data structure here. */ |
| 141 | + public TwoSum() { |
| 142 | + map = new HashMap<>(); |
| 143 | + list = new LinkedList<>(); |
| 144 | + } |
| 145 | + |
| 146 | + /** Add the number to an internal data structure..*/ |
| 147 | + public void add(int number) { |
| 148 | + if(map.containsKey(number)){ |
| 149 | + map.put(number,true); |
| 150 | + }else{ |
| 151 | + map.put(number,false); |
| 152 | + list.add(number); |
| 153 | + low = Math.min(low,number); |
| 154 | + high = Math.max(high,number); |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + /** Find if there exists any pair of numbers which sum is equal |
| 159 | + * to the value. */ |
| 160 | + public boolean find(int value) { |
| 161 | + if(value < 2* low || value > 2*high) return false; |
| 162 | + for(int num : list){ |
| 163 | + int target = value - num; |
| 164 | + if(map.containsKey(target)){ |
| 165 | + if(num != target) return true; |
| 166 | + else if(map.get(target)) return true; |
| 167 | + } |
| 168 | + } |
| 169 | + return false; |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +``` |
| 174 | +
|
| 175 | +### Complexity Analysis |
| 176 | +
|
| 177 | +- **Time Complexity**: $O(\log m \cdot n + \log n \cdot m)$, where $m$ is the number of rows and $n$ is the number of columns. |
| 178 | + |
| 179 | +- **Space complexity**: $O(1)$, as we are using a constant amount of extra space for variables and no additional data structures. |
0 commit comments