Largest Rectangle in Histogram
Keep a stack of indices with increasing heights. When bar i is shorter than (or equal to) the top, the top's rectangle can't go past i, so i is its right wall. Pop it. The bar now under it is shorter than it (the stack is increasing), so that is its left wall. Area = height × (i − left − 1). A fake bar of height 0 at i = n pops whatever is left.
The heights on the stack always increase from bottom to top. So the bar just under any bar is the nearest bar to its left that is shorter: its left wall.
Problem
You are given an array heights that describes a bar chart. Bar i has width 1 and height heights[i], and the bars stand side by side with no gaps.
Find the largest area of a rectangle that fits completely inside the bars. The rectangle covers whole bars that are next to each other, and it can be no taller than the shortest bar it covers.
An integer array heights.
One integer: the area of the largest rectangle.
Bars 5 and 6 (indices 2 and 3) are both at least 5 tall, so a rectangle of height 5 and width 2 fits: area 10. Nothing bigger fits.
Either the single bar 4 (area 4), or both bars at height 2 (area 2 × 2 = 4).
- • 1 ≤ heights.length ≤ 10^5
- • 0 ≤ heights[i] ≤ 10^4
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
If I pick a block of bars [l … r], how tall can the rectangle over that block be?
- 2.
Every rectangle has a shortest bar inside it. What if I made each bar "the shortest bar" in turn?
- 3.
If bar i is the shortest bar of the rectangle, how far left and right can the rectangle stretch?
- 4.
What stops the rectangle from stretching further?
- 5.
When I read a bar that is shorter than the bars before it, which earlier bars can no longer stretch to the right?
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Fix the left edge, extend right, keep the minimum height so far | O(N²) | O(1) |
| Better | Two stack passes find each bar's walls; a third pass computes the areas | O(N) | O(N) |
| Optimal | Pop a bar when a shorter one arrives; the arrival is its right wall, the new top is its left wall | O(N) | O(N) |
Why does this belong to this pattern?
- “largest rectangle”The height of a rectangle is the minimum bar it covers → think about each bar as the minimum.
- “bars side by side”A contiguous range. Each bar's range is limited by the nearest shorter bar on each side.
- “up to 10^5 bars”O(n²) is too slow. We need each bar's walls in O(1) amortized → monotonic stack.
This is the anchor of the contribution sub-pattern: for each element, find how far it stretches as the minimum. Here we take the max of height × width, so ties don't change the answer. In Sum of Subarray Minimums we add up every element's share, and then the tie rule decides whether a subarray is counted once or twice.
Don't make this mistake
Taller bars to the left of j were popped earlier, but they still belong to j's rectangle. The left wall is the bar under j on the stack. In [2, 1, 5, 6, 2, 3], bar 1 is popped at the end with an empty stack: its width is 6 (all bars), not 5.
An empty stack after the pop means no bar on the left is shorter. The rectangle reaches index 0, so the width is i. Reading st.back() on an empty vector is undefined behaviour.
Bars with no shorter bar to their right are never popped inside the loop. For [1, 2, 3, 4, 5] nothing is popped at all and the answer would be 0 instead of 9. The height-0 bar at i = n pops them with right wall n.
The biggest area is at most n × max height = 10^5 × 10^4 = 10^9, which fits in an int (limit about 2.1·10^9). So int is fine. If the limits were bigger (say heights up to 10^9), you would need long long for height * width.
Pattern-confusion trap. In Container With Most Water the water level depends only on the two end lines, so moving the shorter end inward is safe. Here every bar inside the rectangle limits its height, so the minimum of the whole range matters and moving an end pointer can skip the answer. Use each bar as the minimum and find its walls with a stack.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Monotonic Stack translate into production architectures and low-level memory mechanics.