Largest Rectangle In Histogram

Problem

You are given an array of integers heights where heights[i] represents the height of a bar. The width of each bar is 1.

Return the area of the largest rectangle that can be formed among the bars.

Note: This chart is known as a histogram.

Examples

Example 1:

Input: heights = [7,1,7,2,2,4]

Output: 8

Example 2:

Input: heights = [1,3,7]

Output: 7

Constraints

  • 1 <= heights.length <= 1000.
  • 0 <= heights[i] <= 1000

You should aim for a solution with O(n) time and O(n) space, where n is the size of the input array.

Solution

We perform multiple passes, tracking the left and right boundaries for each index. A final pass then lets us find the width and thus area.

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        const int N = heights.size();
 
        // leftMost[i] stores index of nearest bar to the left of i
        //   that is strictly smaller than height[i]
        std::vector<int> leftMost(N, -1);
        // rightMost[i] stores index of nearest bar to the right of i
        //   that is strictly smaller than height[i]
        std::vector<int> rightMost(N, N);
 
        std::stack<int> st;
 
        // Find nearest strictly smaller bar on the left for each i
        for (int i = 0; i < N; ++i) {
            // Remove bars that are >= height
            while (!st.empty() && heights[st.top()] >= heights[i]) {
                st.pop();
            }
            // If stack is non-empty, top is nearest index to left with small height
            if (!st.empty()) { leftMost[i] = st.top(); }
            // Add current bar for future bars to consider
            st.push(i);
        }
 
        // Clear stack so we can resuse for right side
        while (!st.empty()) { st.pop(); }
 
        // Find nearest strictly smaller bar to the right for each i
        for (int i = N - 1; i >= 0; --i) {
            // Remove bars that are >= height
            while (!st.empty() && heights[st.top()] >= heights[i]) {
                st.pop();
            }
            // If stack is non-empty, top is nearest index to left with small height
            if (!st.empty()) { rightMost[i] = st.top(); }
            // Add current bar for future bars to consider
            st.push(i);
        }
 
        int max_area = 0;
        for (int i = 0; i < N; ++i) {
            // First smaller bars are exclusded from the rectangle
            int width = rightMost[i] - leftMost[i] + 1 - 2;
            int area = heights[i] * width;
            max_area = std::max(max_area, area);
        }
 
        return max_area;
    }
};