85. Maximal Rectangle
Given a rows x cols binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.
Example 1:
Input: matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
Output: 6
Explanation: The maximal rectangle is shown in the above picture.
Example 2:
Input: matrix = [[“0”]]
Output: 0
Example 3:
Input: matrix = [[“1”]]
Output: 1
Constraints:
- rows == matrix.length
- cols == matrix[i].length
- 1 <= row, cols <= 200
- matrix[i][j] is ‘0’ or ‘1’.
From: LeetCode
Link: 85. Maximal Rectangle
Solution:
Ideas:
1. Histogram Transformation: Each row in the matrix is transformed into a histogram. The height of the bars in this histogram at each column corresponds to the number of consecutive '1’s up to that row. This means if there’s a ‘1’ above the current ‘1’ in the matrix, the bar gets taller by 1. If there’s a ‘0’, the bar’s height resets to zero.
2. Maximal Rectangle in Histogram: For each histogram created from each row of the matrix, the code calculates the area of the largest rectangle that can be formed in that histogram. This calculation is where the stack is used.
- Using a Stack: The idea is to maintain a stack of indices of the histogram’s bars. Bars are pushed onto the stack if they’re taller than the bar at the stack’s top index. When a shorter bar is encountered, it triggers a calculation:
- Pop the stack until the current bar is taller than the bar at the top of the stack or the stack is empty.
- For each popped bar, calculate the rectangle’s area with the popped bar as the shortest bar (height). The width of this rectangle extends from the current bar’s index to the index just beyond the last bar that was less than the popped bar (as indicated by the new top of the stack).
- Update the maximum area found so far.
3. Iterate Over All Rows: The process is repeated for every row in the matrix, treating each row as the base for a new histogram. This effectively leverages the previous rows’ calculations to build upon them dynamically.
4. Edge Cases: The code handles matrices of any size, including the smallest possible matrix (1x1) and ensures that no memory overflows or illegal accesses occur.
5. Maximal Rectangle Calculation: After processing all rows, the largest area calculated from any histogram is the area of the largest rectangle containing only '1’s in the entire matrix.
Code:
int maximalHistogram(int* heights, int size) {
if (size == 0) return 0;
int *stack = (int *) malloc(sizeof(int) * size);
if (!stack) return 0; // Memory allocation check
int top = -1;
int maxArea = 0;
int area = 0;
int i = 0;
while (i <= size) {
int h = (i == size) ? 0 : heights[i];
while (top != -1 && h < heights[stack[top]]) {
int tp = stack[top--];
int width = (top == -1) ? i : i - stack[top] - 1;
area = heights[tp] * width;
if (area > maxArea) {
maxArea = area;
}
}
if (i < size) {
stack[++top] = i;
}
i++;
}
free(stack);
return maxArea;
}
int maximalRectangle(char** matrix, int matrixSize, int* matrixColSize) {
if (matrixSize == 0 || matrixColSize[0] == 0) return 0;
int maxArea = 0;
int *heights = (int *) calloc(matrixColSize[0], sizeof(int));
if (!heights) return 0; // Memory allocation check
for (int i = 0; i < matrixSize; i++) {
for (int j = 0; j < matrixColSize[i]; j++) {
heights[j] = matrix[i][j] == '1' ? heights[j] + 1 : 0;
}
int currentArea = maximalHistogram(heights, matrixColSize[i]);
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
free(heights);
return maxArea;
}