Bird
Raised Fist0
Interview Prepstacks-monotonic-stackhardAmazonFacebookGoogle

Maximal Rectangle (Matrix to Histogram)

Choose your preparation mode4 modes available
🎯
Maximal Rectangle (Matrix to Histogram)
hardSTACKAmazonFacebookGoogle

Imagine you are analyzing satellite images represented as binary matrices, and you want to find the largest rectangular area of clear land (1s) to build a facility.

💡 This problem combines matrix traversal with stack-based histogram analysis. Beginners often struggle because it requires transforming a 2D problem into multiple 1D histogram problems and then applying a monotonic stack technique to find the largest rectangle efficiently.
📋
Problem Statement

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. Input: a 2D list of characters '0' or '1'. Output: an integer representing the area of the largest rectangle of 1's.

1 ≤ number of rows ≤ 2001 ≤ number of columns ≤ 200Each element is '0' or '1'
💡
Example
Input"[[\"1\",\"0\",\"1\",\"0\",\"0\"],[\"1\",\"0\",\"1\",\"1\",\"1\"],[\"1\",\"1\",\"1\",\"1\",\"1\"],[\"1\",\"0\",\"0\",\"1\",\"0\"]]"
Output6

The largest rectangle of 1's has area 6, formed in the third row spanning columns 1 to 5.

  • Empty matrix → 0
  • Matrix with all zeros → 0
  • Matrix with all ones → total area
  • Single row matrix → largest consecutive ones count
⚠️
Common Mistakes
Not resetting histogram heights to zero when encountering '0' in matrix row

Incorrect histogram heights lead to wrong area calculations

✅ Reset heights[i] = 0 when matrix[row][i] == '0'

Forgetting to add a sentinel zero at the end of heights array in largest rectangle calculation

Stack not fully flushed, missing some area calculations

✅ Append a zero height at the end before processing

Using incorrect width calculation when popping from stack

Area computed is too large or too small, leading to wrong max area

✅ Width = current_index - stack_top - 1 if stack not empty, else current_index

Trying to solve maximal rectangle directly without histogram transformation

Complex nested loops and inefficient code, often leading to TLE

✅ Transform each row into histogram heights and solve largest rectangle in histogram

Not handling empty matrix or empty rows

Runtime errors or exceptions

✅ Add checks for empty input before processing

🧠
Brute Force (Check All Rectangles)
💡 This approach exists to build intuition by trying every possible rectangle, helping understand the problem's nature and why optimization is needed.

Intuition

Check every possible rectangle in the matrix by iterating over all pairs of rows and columns, verifying if all elements are 1, and track the maximum area.

Algorithm

  1. Iterate over all pairs of rows (top and bottom).
  2. For each pair, iterate over all columns to check if all elements between these rows are 1.
  3. For each valid column range, calculate the area and update the maximum.
  4. Return the maximum area found.
💡 The nested loops and checks make it hard to see the inefficiency and the need for better methods.
</>
Code
def maximalRectangle(matrix):
    if not matrix or not matrix[0]:
        return 0
    max_area = 0
    rows, cols = len(matrix), len(matrix[0])
    for top in range(rows):
        for bottom in range(top, rows):
            width = 0
            for col in range(cols):
                all_ones = True
                for row in range(top, bottom + 1):
                    if matrix[row][col] == '0':
                        all_ones = False
                        break
                if all_ones:
                    width += 1
                    max_area = max(max_area, width * (bottom - top + 1))
                else:
                    width = 0
    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 not matrix or not matrix[0]:Check for empty input to avoid errors
for top in range(rows):Select the top row of the rectangle
for bottom in range(top, rows):Select the bottom row of the rectangle
for col in range(cols):Iterate over columns to find continuous 1s
for row in range(top, bottom + 1):Check if all elements in this column between top and bottom are 1
if matrix[row][col] == '0':If any zero found, this column can't be part of rectangle
width += 1Increase width for continuous columns of all ones
max_area = max(max_area, width * (bottom - top + 1))Update max area with current rectangle
public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
        int maxArea = 0;
        int rows = matrix.length, cols = matrix[0].length;
        for (int top = 0; top < rows; top++) {
            for (int bottom = top; bottom < rows; bottom++) {
                int width = 0;
                for (int col = 0; col < cols; col++) {
                    boolean allOnes = true;
                    for (int row = top; row <= bottom; row++) {
                        if (matrix[row][col] == '0') {
                            allOnes = false;
                            break;
                        }
                    }
                    if (allOnes) {
                        width++;
                        maxArea = Math.max(maxArea, width * (bottom - top + 1));
                    } else {
                        width = 0;
                    }
                }
            }
        }
        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 (matrix == null || matrix.length == 0 || matrix[0].length == 0)Check for empty input to avoid exceptions
for (int top = 0; top < rows; top++)Select top row of rectangle
for (int bottom = top; bottom < rows; bottom++)Select bottom row of rectangle
for (int col = 0; col < cols; col++)Iterate columns to find continuous ones
for (int row = top; row <= bottom; row++)Check all rows in current column for ones
if (matrix[row][col] == '0')Break if zero found in column
width++Increase width for continuous columns of ones
maxArea = Math.max(maxArea, width * (bottom - top + 1))Update max area with current rectangle
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int maximalRectangle(vector<vector<char>>& matrix) {
    if (matrix.empty() || matrix[0].empty()) return 0;
    int maxArea = 0;
    int rows = matrix.size(), cols = matrix[0].size();
    for (int top = 0; top < rows; ++top) {
        for (int bottom = top; bottom < rows; ++bottom) {
            int width = 0;
            for (int col = 0; col < cols; ++col) {
                bool allOnes = true;
                for (int row = top; row <= bottom; ++row) {
                    if (matrix[row][col] == '0') {
                        allOnes = false;
                        break;
                    }
                }
                if (allOnes) {
                    ++width;
                    maxArea = max(maxArea, width * (bottom - top + 1));
                } else {
                    width = 0;
                }
            }
        }
    }
    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 (matrix.empty() || matrix[0].empty()) return 0;Check for empty input to avoid errors
for (int top = 0; top < rows; ++top)Select top row of rectangle
for (int bottom = top; bottom < rows; ++bottom)Select bottom row of rectangle
for (int col = 0; col < cols; ++col)Iterate columns to find continuous ones
for (int row = top; row <= bottom; ++row)Check all rows in current column for ones
if (matrix[row][col] == '0')Break if zero found in column
++width;Increase width for continuous columns of ones
maxArea = max(maxArea, width * (bottom - top + 1));Update max area with current rectangle
var maximalRectangle = function(matrix) {
    if (!matrix.length || !matrix[0].length) return 0;
    let maxArea = 0;
    let rows = matrix.length, cols = matrix[0].length;
    for (let top = 0; top < rows; top++) {
        for (let bottom = top; bottom < rows; bottom++) {
            let width = 0;
            for (let col = 0; col < cols; col++) {
                let allOnes = true;
                for (let row = top; row <= bottom; row++) {
                    if (matrix[row][col] === '0') {
                        allOnes = false;
                        break;
                    }
                }
                if (allOnes) {
                    width++;
                    maxArea = Math.max(maxArea, width * (bottom - top + 1));
                } else {
                    width = 0;
                }
            }
        }
    }
    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 (!matrix.length || !matrix[0].length) return 0;Check for empty input to avoid errors
for (let top = 0; top < rows; top++)Select top row of rectangle
for (let bottom = top; bottom < rows; bottom++)Select bottom row of rectangle
for (let col = 0; col < cols; col++)Iterate columns to find continuous ones
for (let row = top; row <= bottom; row++)Check all rows in current column for ones
if (matrix[row][col] === '0')Break if zero found in column
width++Increase width for continuous columns of ones
maxArea = Math.max(maxArea, width * (bottom - top + 1))Update max area with current rectangle
⏱
Complexity
TimeO(rows^2 * cols^2)
SpaceO(1)

We check all pairs of rows (O(rows^2)) and for each pair, all columns (O(cols)) and for each column, check all rows between top and bottom (O(rows)), resulting in O(rows^2 * cols * rows) = O(rows^3 * cols), but since rows and cols are similar, simplified to O(rows^2 * cols^2).

💡 For a 10x10 matrix, this means 10^2 * 10^2 = 10,000 operations, which is manageable, but for 200x200 it becomes 160 million operations, too slow for interviews.
Interview Verdict: TLE

This approach is too slow for large inputs but helps understand the problem and motivates better solutions.

🧠
Row-wise Histogram + Largest Rectangle in Histogram (Stack)
💡 This approach improves efficiency by converting each row into a histogram and applying a known stack-based algorithm to find the largest rectangle in a histogram.

Intuition

For each row, build a histogram of heights representing consecutive ones above, then use a monotonic stack to find the largest rectangle in the current histogram.

Algorithm

  1. Initialize a heights array with zeros for each column.
  2. For each row, update heights: increment if '1', reset to 0 if '0'.
  3. Use a monotonic stack to find the largest rectangle in the current histogram.
  4. Track and update the maximum area found.
💡 The key insight is transforming the 2D problem into multiple 1D problems and efficiently solving each with a stack.
</>
Code
def largestRectangleArea(heights):
    stack = []
    max_area = 0
    for i, h in enumerate(heights + [0]):
        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
stack = []Initialize stack to store indices of bars
for i, h in enumerate(heights + [0]):Add sentinel zero height to flush stack at end
while stack and heights[stack[-1]] > h:Pop bars taller than current to calculate area
height = heights[stack.pop()]Height of popped bar for area calculation
width = i if not stack else i - stack[-1] - 1Calculate width based on current and stack top
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 processing 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];
            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
Stack<Integer> stack = new Stack<>();Stack to store indices of bars
for (int i = 0; i <= heights.length; i++)Iterate with sentinel to flush stack
while (!stack.isEmpty() && heights[stack.peek()] > h)Pop bars taller than current for area calc
int width = stack.isEmpty() ? i : i - stack.peek() - 1;Calculate width for popped bar
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;
    heights.push_back(0); // sentinel
    for (int i = 0; i < (int)heights.size(); ++i) {
        while (!st.empty() && heights[st.top()] > heights[i]) {
            int height = heights[st.top()]; st.pop();
            int width = st.empty() ? i : i - st.top() - 1;
            maxArea = max(maxArea, height * width);
        }
        st.push(i);
    }
    heights.pop_back();
    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
stack<int> st;Stack to store indices of bars
heights.push_back(0);Add sentinel to flush stack at end
while (!st.empty() && heights[st.top()] > heights[i])Pop bars taller than current for area calc
int width = st.empty() ? i : i - st.top() - 1;Calculate width for popped bar
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;
    heights.push(0); // sentinel
    for (let i = 0; i < heights.length; i++) {
        while (stack.length && heights[stack[stack.length - 1]] > heights[i]) {
            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);
    }
    heights.pop();
    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
let stack = [];Stack to store indices of bars
heights.push(0);Add sentinel to flush stack at end
while (stack.length && heights[stack[stack.length - 1]] > heights[i])Pop bars taller than current for area calc
let width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;Calculate width for popped bar
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
⏱
Complexity
TimeO(rows * cols)
SpaceO(cols)

For each row, we update heights in O(cols) and compute largest rectangle in histogram in O(cols), total O(rows * cols).

💡 For a 200x200 matrix, this means 40,000 operations, which is efficient for interviews.
Interview Verdict: Accepted

This approach is optimal and commonly expected in interviews for this problem.

🧠
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

  1. Build histogram heights row by row as before.
  2. Skip columns with zero height when pushing to the stack.
  3. Use monotonic stack to calculate largest rectangle efficiently.
  4. Update maximum area accordingly.
💡 This subtle optimization reduces stack operations but does not change overall complexity.
</>
Code
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
⏱
Complexity
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.

📊
All Approaches - One-Glance Tradeoffs
💡 The stack-based histogram approach (Approach 2) is the best to code in interviews due to its optimal time and clarity.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Brute ForceO(rows^2 * cols^2)O(1)NoN/AMention only - never code
2. Row-wise Histogram + Monotonic StackO(rows * cols)O(cols)NoYesCode this approach
3. Optimized Histogram CalculationO(rows * cols)O(cols)NoYesOptional optimization
💼
Interview Strategy
💡 Use this guide to understand the problem deeply, practice coding all approaches, and prepare to explain tradeoffs clearly in interviews.

How to Present

Step 1: Clarify input format and constraints.Step 2: Describe brute force approach and its inefficiency.Step 3: Introduce histogram transformation and largest rectangle in histogram problem.Step 4: Explain monotonic stack solution for largest rectangle in histogram.Step 5: Code the optimal solution and test with examples.

Time Allocation

Clarify: 2min → Approach: 5min → Code: 10min → Test: 3min. Total ~20min

What the Interviewer Tests

Understanding of matrix to histogram transformation, stack usage for largest rectangle, and ability to optimize nested loops.

Common Follow-ups

  • How to handle very large matrices efficiently → Use streaming or early pruning
  • Can this be extended to find the rectangle coordinates → Track indices during stack operations
💡 These follow-ups test deeper understanding and ability to extend solutions beyond basic implementation.
🔍
Pattern Recognition

When to Use

1) Problem involves largest rectangle or area in binary matrix; 2) Matrix contains 0/1 values; 3) Need to find maximal rectangle of 1s; 4) Can transform rows into histograms.

Signature Phrases

'largest rectangle containing only 1's''convert matrix rows to histogram heights'

NOT This Pattern When

Problems asking for maximal square or submatrix sums without rectangle constraints

Similar Problems

Largest Rectangle in Histogram - core subproblem solved with stackMaximal Square - similar matrix problem but for squaresMaximal Rectangle in Binary Matrix - variant with different constraints

Practice

(1/5)
1. What is the time complexity of the dequeue operation in the optimal circular queue implementation using a fixed-size array with head, tail pointers, and a size variable?
medium
A. O(n), because elements need to be shifted after dequeue
B. O(log n), due to pointer arithmetic
C. O(1), because head pointer moves forward with modulo wrap-around
D. O(n), because size variable needs to be updated

Solution

  1. Step 1: Identify complexity of pointer movement

    Dequeue moves head pointer forward by one position modulo capacity, which is a constant time operation.
  2. Step 2: Check if any other operations add complexity

    No shifting of elements or complex calculations occur; size variable update is O(1).
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Dequeue is O(1) due to simple pointer increment and size decrement [OK]
Hint: Pointer increment modulo capacity is O(1) [OK]
Common Mistakes:
  • Assuming shifting elements is needed
  • Confusing pointer arithmetic with logarithmic time
  • Thinking size update is costly
2. Consider this buggy implementation of the pop method in the two-stack queue. What is the bug?
def pop(self) -> int:
    while self.push_stack:
        self.pop_stack.append(self.push_stack.pop())
    return self.pop_stack.pop()
medium
A. The push_stack should be cleared after transfer to avoid duplicates.
B. The pop_stack.pop() call should be replaced with pop_stack[-1] to peek instead of pop.
C. The transfer loop should only run if pop_stack is empty, otherwise elements are transferred every pop causing inefficiency.
D. The method should check if both stacks are empty before popping to avoid runtime errors.

Solution

  1. Step 1: Identify transfer condition

    The code transfers elements from push_stack to pop_stack on every pop, regardless of pop_stack state.
  2. Step 2: Understand impact

    This causes O(n) time on every pop, losing amortized O(1) efficiency.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Transfer only when pop_stack empty -> amortized O(1) [OK]
Hint: Transfer only if pop_stack empty to keep amortized O(1) [OK]
Common Mistakes:
  • Transferring every pop causes O(n) pop time
  • Not checking empty queue before pop
3. Identify the bug in the following MinStack implementation using a single stack with encoded minimums:
medium
A. Line 'if diff < 0:' in pop should be 'if diff <= 0:' to handle zero differences correctly.
B. Line 'self.stack.append(diff)' should append x instead of diff to store actual values.
C. Line with 'if diff <= 0:' should be 'if diff < 0:' to avoid incorrect min updates on duplicates.
D. Line 'self.minVal = self.minVal - diff' in pop should add diff instead of subtracting.

Solution

  1. Step 1: Analyze push condition

    The condition 'if diff <= 0:' updates minVal even when diff == 0, i.e., when new element equals current min.
  2. Step 2: Understand impact

    Updating minVal on equal values causes minVal to be overwritten incorrectly, breaking min tracking when duplicates are popped.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Correct condition is 'diff < 0' to update minVal only on strictly smaller values [OK]
Hint: Only update minVal when new value is strictly less than current min [OK]
Common Mistakes:
  • Using <= instead of < causes minVal errors with duplicates
  • Incorrect pop minVal update
  • Appending wrong values to stack
4. What is the time complexity of the optimal monotonic stack solution that uses an explicit circular array copy (doubling the array) for the Next Greater Element II problem, and why?
medium
A. O(n) because each element is pushed and popped at most once despite doubling
B. O(n²) because the doubled array doubles the iterations
C. O(n log n) due to sorting implicit in stack operations
D. O(2n) which simplifies to O(n) but requires extra space

Solution

  1. Step 1: Identify loop iterations

    The loop runs over doubled array of length 2n, so 2n iterations.
  2. Step 2: Analyze stack operations

    Each element index is pushed once and popped once at most, so total stack operations are O(n). The doubling does not cause repeated pushes for the same index.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Doubling array length does not multiply complexity beyond linear [OK]
Hint: Each element pushed/popped once -> O(n) despite doubled array [OK]
Common Mistakes:
  • Assuming doubling array doubles complexity to O(n²)
  • Confusing stack operations with sorting complexity
  • Ignoring that indices are pushed only once
5. What is the time complexity of the optimized stack-based approach for validating parentheses in a string of length n, and why might some candidates mistakenly think it is higher?
medium
A. O(n^2) because each character might be compared multiple times during matching
B. O(n) because each character is processed once with constant-time stack operations
C. O(n log n) due to sorting or ordering operations on the stack
D. O(n) for time but O(n^2) for space due to stack growth in worst case

Solution

  1. Step 1: Identify complexity of outer loop

    The algorithm iterates over each character exactly once, so the loop is O(n).
  2. Step 2: Check stack operations

    Stack push/pop are O(1) operations, so total time remains O(n). No nested loops or repeated scanning.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Single pass with constant-time stack ops -> O(n) time [OK]
Hint: Each character processed once with O(1) stack ops [OK]
Common Mistakes:
  • Confusing with brute force O(n^2) approach
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard