21. Max Rectangle

βœ… GFG solution to the Max Rectangle problem: find maximum area rectangle in binary matrix using largest rectangle in histogram approach with stack optimization. πŸš€

The problem can be found at the following link: πŸ”— Question Link

🧩 Problem Description

You are given a 2D binary matrix mat[][], where each cell contains either 0 or 1. Your task is to find the maximum area of a rectangle that can be formed using only 1's within the matrix.

A rectangle is formed by selecting a submatrix where all elements are 1. The goal is to find the rectangle with the maximum possible area.

πŸ“˜ Examples

Example 1

Input: mat[][] = [[0, 1, 1, 0],
                  [1, 1, 1, 1],
                  [1, 1, 1, 1],
                  [1, 1, 0, 0]]
Output: 8
Explanation: The largest rectangle with only 1's is from (1, 0) to (2, 3) which is
[1, 1, 1, 1]
[1, 1, 1, 1]
and area is 4 * 2 = 8.

Example 2

Input: mat[][] = [[0, 1, 1],
                  [1, 1, 1],
                  [0, 1, 1]]
Output: 6
Explanation: The largest rectangle with only 1's is from (0, 1) to (2, 2) which is
[1, 1]
[1, 1]
[1, 1]
and area is 2 * 3 = 6.

πŸ”’ Constraints

  • $1 \le \text{mat.size()}, \text{mat[0].size()} \le 1000$

  • $0 \le \text{mat}[i][j] \le 1$

βœ… My Approach

The optimal approach transforms this problem into the Largest Rectangle in Histogram problem by treating each row as the base of a histogram:

Histogram + Stack Approach

  1. Transform to Histogram:

    • For each row, calculate the height of consecutive 1's ending at that row.

    • If mat[i][j] = 1, then height[j] = height[j] + 1

    • If mat[i][j] = 0, then height[j] = 0

  2. Apply Largest Rectangle in Histogram:

    • For each row's histogram, find the maximum rectangle area using stack.

    • Use a monotonic stack to efficiently find the largest rectangle.

  3. Stack Algorithm:

    • Push indices to stack while heights are increasing.

    • When a smaller height is found, pop from stack and calculate area.

    • Width = current_index - previous_stack_top - 1 (or current_index if stack is empty).

  4. Update Maximum:

    • Track the maximum area found across all rows.

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n Γ— m), where n is the number of rows and m is the number of columns. For each row, we process the histogram in O(m) time using stack operations where each element is pushed and popped at most once.

  • Expected Auxiliary Space Complexity: O(m), where m is the number of columns. We use O(m) space for the height array and O(m) space for the stack in the worst case.

πŸ§‘β€πŸ’» Code (C++)

class Solution {
public:
    int maxArea(vector<vector<int>>& mat) {
        int n = mat.size(), m = mat[0].size(), res = 0;
        vector<int> h(m, 0);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) 
                h[j] = mat[i][j] ? h[j] + 1 : 0;
            stack<int> st;
            for (int j = 0; j <= m; j++) {
                int cur = j == m ? 0 : h[j];
                while (!st.empty() && h[st.top()] > cur) {
                    int tp = st.top(); st.pop();
                    int w = st.empty() ? j : j - st.top() - 1;
                    res = max(res, h[tp] * w);
                }
                st.push(j);
            }
        }
        return res;
    }
};
⚑ View Alternative Approaches with Code and Analysis

πŸ“Š 2️⃣ Dynamic Programming with Arrays

πŸ’‘ Algorithm Steps:

  1. For each row, maintain left and right boundaries for each column

  2. Track height of consecutive 1s ending at current row

  3. Calculate width using left and right boundaries

  4. Update maximum area for each position

class Solution {
public:
    int maxArea(vector<vector<int>>& mat) {
        int n = mat.size(), m = mat[0].size(), res = 0;
        vector<int> h(m, 0), l(m, 0), r(m, m);
        for (int i = 0; i < n; i++) {
            int cl = 0, cr = m;
            for (int j = 0; j < m; j++) {
                h[j] = mat[i][j] ? h[j] + 1 : 0;
                l[j] = mat[i][j] ? max(l[j], cl) : (cl = j + 1, 0);
            }
            for (int j = m - 1; j >= 0; j--) {
                r[j] = mat[i][j] ? min(r[j], cr) : (cr = j, m);
                res = max(res, h[j] * (r[j] - l[j]));
            }
        }
        return res;
    }
};

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— m) - Single pass through matrix

  • Auxiliary Space: πŸ’Ύ O(m) - Three arrays for height, left, right

βœ… Why This Approach?

  • Linear time complexity without stack operations

  • More predictable memory access patterns

  • Easier to understand the boundary calculations

πŸ“Š 3️⃣ Divide and Conquer

πŸ’‘ Algorithm Steps:

  1. For each row as base, find maximum rectangle in histogram

  2. Use divide and conquer to split histogram at minimum height

  3. Recursively solve left and right parts

  4. Return maximum of left, right, and cross-section rectangles

class Solution {
private:
    int divide(vector<int>& h, int l, int r) {
        if (l > r) return 0;
        int mid = l;
        for (int i = l + 1; i <= r; i++)
            if (h[i] < h[mid]) mid = i;
        return max({h[mid] * (r - l + 1), 
                   divide(h, l, mid - 1), 
                   divide(h, mid + 1, r)});
    }
public:
    int maxArea(vector<vector<int>>& mat) {
        int n = mat.size(), m = mat[0].size(), res = 0;
        vector<int> h(m, 0);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                h[j] = mat[i][j] ? h[j] + 1 : 0;
            res = max(res, divide(h, 0, m - 1));
        }
        return res;
    }
};

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— mΒ²) - Worst case for divide and conquer

  • Auxiliary Space: πŸ’Ύ O(m) - Recursion stack and height array

βœ… Why This Approach?

  • Natural recursive structure

  • Good for understanding problem decomposition

  • Can be optimized with segment trees

πŸ“Š 4️⃣ Monotonic Deque Optimization

πŸ’‘ Algorithm Steps:

  1. Use deque to maintain indices in increasing order of heights

  2. For each position, pop elements that violate monotonic property

  3. Calculate area using current height and width from deque

  4. More efficient than stack for certain input patterns

class Solution {
public:
    int maxArea(vector<vector<int>>& mat) {
        int n = mat.size(), m = mat[0].size(), res = 0;
        vector<int> h(m, 0);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                h[j] = mat[i][j] ? h[j] + 1 : 0;
            deque<int> dq;
            for (int j = 0; j <= m; j++) {
                int cur = j == m ? 0 : h[j];
                while (!dq.empty() && h[dq.back()] > cur) {
                    int tp = dq.back(); dq.pop_back();
                    int w = dq.empty() ? j : j - dq.back() - 1;
                    res = max(res, h[tp] * w);
                }
                dq.push_back(j);
            }
        }
        return res;
    }
};

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— m) - Linear processing with deque

  • Auxiliary Space: πŸ’Ύ O(m) - Deque and height array

βœ… Why This Approach?

  • Flexible data structure for monotonic operations

  • Better cache locality than stack in some cases

  • Alternative implementation for histogram problem

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

πŸ“š Stack-Based Histogram

🟒 O(n Γ— m)

🟒 O(m)

πŸš€ Optimal and intuitive

πŸ”§ Stack operations overhead

🎯 DP with Arrays

🟒 O(n Γ— m)

🟒 O(m)

πŸ“– No stack, linear scan

πŸ’­ Complex boundary logic

🌳 Divide & Conquer

🟑 O(n Γ— mΒ²)

🟒 O(m)

πŸŽ“ Educational value

🐌 Worst case quadratic time

πŸ“Š Monotonic Deque

🟒 O(n Γ— m)

🟒 O(m)

πŸ”„ Flexible structure

πŸ”§ Similar to stack approach

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

πŸ… General optimal performance

πŸ₯‡ Stack-Based Histogram

β˜…β˜…β˜…β˜…β˜…

πŸ“– Avoid stack operations

πŸ₯ˆ DP with Arrays

β˜…β˜…β˜…β˜…β˜†

πŸŽ“ Learning/Educational

πŸ₯‰ Divide & Conquer

β˜…β˜…β˜…β˜†β˜†

πŸ”§ Alternative implementation

πŸ… Monotonic Deque

β˜…β˜…β˜…β˜…β˜†

β˜• Code (Java)

class Solution {
    static int maxArea(int mat[][]) {
        int n = mat.length, m = mat[0].length, res = 0;
        int[] h = new int[m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                h[j] = mat[i][j] == 1 ? h[j] + 1 : 0;
            Stack<Integer> st = new Stack<>();
            for (int j = 0; j <= m; j++) {
                int cur = j == m ? 0 : h[j];
                while (!st.isEmpty() && h[st.peek()] > cur) {
                    int tp = st.pop();
                    int w = st.isEmpty() ? j : j - st.peek() - 1;
                    res = Math.max(res, h[tp] * w);
                }
                st.push(j);
            }
        }
        return res;
    }
}

🐍 Code (Python)

class Solution:
    def maxArea(self, mat):
        n, m, res = len(mat), len(mat[0]), 0
        h = [0] * m
        for i in range(n):
            for j in range(m):
                h[j] = h[j] + 1 if mat[i][j] else 0
            st = []
            for j in range(m + 1):
                cur = 0 if j == m else h[j]
                while st and h[st[-1]] > cur:
                    tp = st.pop()
                    w = j if not st else j - st[-1] - 1
                    res = max(res, h[tp] * w)
                st.append(j)
        return res

Note: This Python approach sometimes results in Time Limit Exceeded (TLE) for large inputs (fails ~1110 /1115 test cases due to time constraints).

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated