🧠
Optimized Histogram Calculation with Early Skips
💡 This approach is a refinement of the previous one, adding minor optimizations to skip unnecessary calculations when possible.
Intuition
While building histograms row by row, skip columns that are zero early to reduce unnecessary stack operations.
Algorithm
- Build histogram heights row by row as before.
- Skip columns with zero height when pushing to the stack.
- Use monotonic stack to calculate largest rectangle efficiently.
- Update maximum area accordingly.
💡 This subtle optimization reduces stack operations but does not change overall complexity.
def largestRectangleArea(heights):
stack = []
max_area = 0
for i, h in enumerate(heights + [0]):
if h == 0:
while stack:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
else:
while stack and heights[stack[-1]] > h:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
stack.append(i)
return max_area
def maximalRectangle(matrix):
if not matrix or not matrix[0]:
return 0
max_area = 0
cols = len(matrix[0])
heights = [0] * cols
for row in matrix:
for i in range(cols):
heights[i] = heights[i] + 1 if row[i] == '1' else 0
max_area = max(max_area, largestRectangleArea(heights))
return max_area
# Example usage:
matrix = [
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
print(maximalRectangle(matrix)) # Output: 6
Line Notes
if h == 0:Flush stack early when zero height encountered
while stack:Pop all bars to calculate area when zero found
while stack and heights[stack[-1]] > h:Pop taller bars for area calculation
stack.append(i)Push current index to stack
heights[i] = heights[i] + 1 if row[i] == '1' else 0Update histogram heights for current row
max_area = max(max_area, largestRectangleArea(heights))Update max area after each row
import java.util.Stack;
public class Solution {
public int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
int maxArea = 0;
for (int i = 0; i <= heights.length; i++) {
int h = (i == heights.length) ? 0 : heights[i];
if (h == 0) {
while (!stack.isEmpty()) {
int height = heights[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
} else {
while (!stack.isEmpty() && heights[stack.peek()] > h) {
int height = heights[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
}
return maxArea;
}
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
int maxArea = 0;
int cols = matrix[0].length;
int[] heights = new int[cols];
for (char[] row : matrix) {
for (int i = 0; i < cols; i++) {
heights[i] = (row[i] == '1') ? heights[i] + 1 : 0;
}
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
public static void main(String[] args) {
Solution sol = new Solution();
char[][] matrix = {
{'1','0','1','0','0'},
{'1','0','1','1','1'},
{'1','1','1','1','1'},
{'1','0','0','1','0'}
};
System.out.println(sol.maximalRectangle(matrix)); // Output: 6
}
}
Line Notes
if (h == 0) {Flush stack early when zero height encountered
while (!stack.isEmpty()) {Pop all bars to calculate area when zero found
while (!stack.isEmpty() && heights[stack.peek()] > h) {Pop taller bars for area calculation
stack.push(i);Push current index to stack
heights[i] = (row[i] == '1') ? heights[i] + 1 : 0;Update histogram heights for current row
maxArea = Math.max(maxArea, largestRectangleArea(heights));Update max area after each row
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
int largestRectangleArea(vector<int>& heights) {
stack<int> st;
int maxArea = 0;
for (int i = 0; i <= (int)heights.size(); ++i) {
int h = (i == (int)heights.size()) ? 0 : heights[i];
if (h == 0) {
while (!st.empty()) {
int height = heights[st.top()]; st.pop();
int width = st.empty() ? i : i - st.top() - 1;
maxArea = max(maxArea, height * width);
}
} else {
while (!st.empty() && heights[st.top()] > h) {
int height = heights[st.top()]; st.pop();
int width = st.empty() ? i : i - st.top() - 1;
maxArea = max(maxArea, height * width);
}
st.push(i);
}
}
return maxArea;
}
int maximalRectangle(vector<vector<char>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return 0;
int maxArea = 0;
int cols = matrix[0].size();
vector<int> heights(cols, 0);
for (auto& row : matrix) {
for (int i = 0; i < cols; ++i) {
heights[i] = (row[i] == '1') ? heights[i] + 1 : 0;
}
maxArea = max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
int main() {
vector<vector<char>> matrix = {
{'1','0','1','0','0'},
{'1','0','1','1','1'},
{'1','1','1','1','1'},
{'1','0','0','1','0'}
};
cout << maximalRectangle(matrix) << endl; // Output: 6
return 0;
}
Line Notes
if (h == 0) {Flush stack early when zero height encountered
while (!st.empty()) {Pop all bars to calculate area when zero found
while (!st.empty() && heights[st.top()] > h) {Pop taller bars for area calculation
st.push(i);Push current index to stack
heights[i] = (row[i] == '1') ? heights[i] + 1 : 0;Update histogram heights for current row
maxArea = max(maxArea, largestRectangleArea(heights));Update max area after each row
var largestRectangleArea = function(heights) {
let stack = [];
let maxArea = 0;
for (let i = 0; i <= heights.length; i++) {
let h = (i === heights.length) ? 0 : heights[i];
if (h === 0) {
while (stack.length) {
let height = heights[stack.pop()];
let width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;
maxArea = Math.max(maxArea, height * width);
}
} else {
while (stack.length && heights[stack[stack.length - 1]] > h) {
let height = heights[stack.pop()];
let width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
}
return maxArea;
};
var maximalRectangle = function(matrix) {
if (!matrix.length || !matrix[0].length) return 0;
let maxArea = 0;
let cols = matrix[0].length;
let heights = new Array(cols).fill(0);
for (let row of matrix) {
for (let i = 0; i < cols; i++) {
heights[i] = row[i] === '1' ? heights[i] + 1 : 0;
}
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
};
// Example usage:
const matrix = [
['1','0','1','0','0'],
['1','0','1','1','1'],
['1','1','1','1','1'],
['1','0','0','1','0']
];
console.log(maximalRectangle(matrix)); // Output: 6
Line Notes
if (h === 0) {Flush stack early when zero height encountered
while (stack.length) {Pop all bars to calculate area when zero found
while (stack.length && heights[stack[stack.length - 1]] > h) {Pop taller bars for area calculation
stack.push(i);Push current index to stack
heights[i] = row[i] === '1' ? heights[i] + 1 : 0;Update histogram heights for current row
maxArea = Math.max(maxArea, largestRectangleArea(heights));Update max area after each row
TimeO(rows * cols)
SpaceO(cols)
Same asymptotic complexity as previous approach, but with fewer stack operations in practice.
💡 This optimization is subtle and mainly improves runtime constants, not big-O.
Interview Verdict: Accepted
This is a fine optimization but not required; the previous approach is sufficient in interviews.