Find the Minimum Area to Cover All Ones II

Hard
Watch on YouTube ↗

Solution

class Solution {
    public int minimumSum(int[][] grid) {
        
        int rows = grid.length;
        int cols = grid[0].length;

        int minarea = Integer.MAX_VALUE;

       // Case 1: Try splitting along rows
        for (int cutRow = 1; cutRow <= rows; cutRow++) {
            // First rectangle covers [0..cutRow)
            int topRect = getBoundingBoxArea(grid, 0, 0, cutRow, cols);
            // First rectangle covers [cutRow..rows)
            int bottomRect = getBoundingBoxArea(grid, cutRow, 0, rows, cols);

            minarea = Math.min(minarea,
                Math.min(
                    /*
                    <<Top Rect + Split Horizontal>>

                        +-----------+
                        |     1     |
                        +-----+-----+
                        |  2  |  3  |
                        +-----+-----+
                    */
                    topRect + splitHorizontal(grid, cutRow, 0, rows, cols),
                    Math.min(
                            /*<<Bottom Rect + Split Horizontal>>
                            +-----+-----+
                            |  1  |  2  |
                            +-----+-----+
                            |     3     |
                            +-----------+*/

                        bottomRect + splitHorizontal(grid, 0, 0, cutRow, cols),

                        /*

                     <<Bottom Rect + Split Vertical>>
                            +-----------+
                            |     1     |
                            +-----------+
                            |     2     |
                            +-----------+
                            |     3     |
                            +-----------+*/
                        bottomRect + splitVertical(grid, 0, 0, cutRow, cols)
                    )
                )
            );
        }

         // Case 2: Try splitting along columns
        for (int cutCol = 1; cutCol <= cols; cutCol++) {
            // First rectangle covers [0..cutCol)
            int leftRect = getBoundingBoxArea(grid, 0, 0, rows, cutCol);
            // First rectangle covers [cutCol..cols)
            int rightRect = getBoundingBoxArea(grid, 0, cutCol, rows, cols);

            minarea = Math.min(minarea,
                Math.min(
                    leftRect + splitVertical(grid, 0, cutCol, rows, cols),
                    Math.min(
                        rightRect + splitVertical(grid, 0, 0, rows, cutCol),
                        rightRect + splitHorizontal(grid, 0, 0, rows, cutCol)
                    )
                )
            );
        }

        return minarea;

    }


    // Compute min area using 2 rectangles (split horizontally → left + right)
    /*
        +-----------+
        |     1     |
        +-----+-----+
        |  2  |  3  |
        +-----+-----+
    */
    private int splitHorizontal(int[][] grid, int rowStart, int colStart, int rowEnd, int colEnd) {
        int minArea = Integer.MAX_VALUE;
        for (int midCol = colStart + 1; midCol <= colEnd; midCol++) {
            int leftArea = getBoundingBoxArea(grid, rowStart, colStart, rowEnd, midCol);
            int rightArea = getBoundingBoxArea(grid, rowStart, midCol, rowEnd, colEnd);
            minArea = Math.min(minArea, leftArea + rightArea);
        }
        return minArea;
    }

    
        private int splitVertical(int[][] grid, int rowStart, int colStart, int rowEnd, int colEnd) {
        int minArea = Integer.MAX_VALUE;
        for (int midRow = rowStart + 1; midRow <= rowEnd; midRow++) {
            int topArea = getBoundingBoxArea(grid, rowStart, colStart, midRow, colEnd);
            int bottomArea = getBoundingBoxArea(grid, midRow, colStart, rowEnd, colEnd);
            minArea = Math.min(minArea, topArea + bottomArea);
        }
        return minArea;
    }

    private int getBoundingBoxArea(int[][] grid, int rowStart, int colStart, int rowEnd, int colEnd) {
        int minRow = Integer.MAX_VALUE, minCol = Integer.MAX_VALUE;
        int maxRow = -1, maxCol = -1;

        for (int i = rowStart; i < rowEnd; i++) {
            for (int j = colStart; j < colEnd; j++) {
                if (grid[i][j] == 1) {
                    minRow = Math.min(minRow, i);
                    minCol = Math.min(minCol, j);
                    maxRow = Math.max(maxRow, i);
                    maxCol = Math.max(maxCol, j);
                }
            }
        }

        // No 1s found → area = 0
        if (maxRow == -1) return 0;

        return (maxRow - minRow + 1) * (maxCol - minCol + 1);
    }
}

/*

Horizontal Split

<<Top Rect + Split Horizontal>>

+-----------+
|     1     |
+-----+-----+
|  2  |  3  |
+-----+-----+

<<Bottom Rect + Split Horizontal>>
+-----+-----+
|  1  |  2  |
+-----+-----+
|     3     |
+-----------+

<<Bottom Rect + Split Vertical>>
+-----------+
|     1     |
+-----------+
|     2     |
+-----------+
|     3     |
+-----------+


Vertical Split

<<left rect + Split Vertical>>

+-----+-----+
|     |  2  |
+  1  +-----|
|     |   3 |
+-----+-----+

<<Right Rect + Split Vertical>>

+-----+-----+
|  1  |     |
+-----+  3  |
|  2  |     |
+-----+-----+


<<Right Rect  + Split Horizontal>>
+-----+-----+-----+
|  1  |  2  |  3  |
+-----+-----+-----+



Yesterday's area finding code:

 private int getBoundingBoxArea(int[][] grid, int rowStart, int colStart, int rowEnd, int colEnd) {
        int minRow = Integer.MAX_VALUE, minCol = Integer.MAX_VALUE;
        int maxRow = -1, maxCol = -1;

        for (int i = rowStart; i < rowEnd; i++) {
            for (int j = colStart; j < colEnd; j++) {
                if (grid[i][j] == 1) {
                    minRow = Math.min(minRow, i);
                    minCol = Math.min(minCol, j);
                    maxRow = Math.max(maxRow, i);
                    maxCol = Math.max(maxCol, j);
                }
            }
        }

        // No 1s found → area = 0
        if (maxRow == -1) return 0;

        return (maxRow - minRow + 1) * (maxCol - minCol + 1);
    }

*/