HardStack

Largest Rectangle in Histogram โ€” Solution

Problem

You are given an array of bar heights representing a histogram where each bar has width 1. Find the area of the largest rectangle that can be formed using consecutive bars โ€” the rectangle's height is capped by the shortest bar it spans.

  • Input: heights = [2, 1, 5, 6, 2, 3]
  • Output: 10
  • Explanation: The rectangle spanning bars at indices 2 and 3 (heights 5 and 6) has height 5 and width 2, giving area 10.

A useful counter-example: heights = [3, 1, 3] produces area 3, not 9 โ€” the center bar of height 1 prevents the two outer bars from forming a single wide rectangle.

Intuition

A rectangle's height is always limited by its shortest bar, so expanding a rectangle rightward helps only as long as we do not encounter something shorter. Instead of checking every possible pair of left and right edges (O(nยฒ)), we can process each bar exactly once by maintaining a stack of bars that are still "open" candidates โ€” bars whose widest possible rectangle has not yet been determined because nothing shorter has blocked them on the right. The instant a shorter bar appears, every taller bar in the stack has found its right boundary.

Approach 1 โ€” Brute Force

For every possible left edge, scan rightward while tracking the minimum height seen. The current rectangle's height is that running minimum; update the max area at each step.

  1. Loop over every starting index left.
  2. Initialize min_height to heights[left].
  3. Loop right from left to n-1.
  4. Update min_height = min(min_height, heights[right]).
  5. Update max_area = max(max_area, min_height * (right - left + 1)).
  6. Return max_area.
1class Solution:
2    def largestRectangleArea(self, heights: list[int]) -> int:
3        max_area = 0
4        for left in range(len(heights)):
5            min_height = heights[left]  # tallest the rectangle can be starting here
6            for right in range(left, len(heights)):
7                min_height = min(min_height, heights[right])  # shrinks as we hit shorter bars
8                max_area = max(max_area, min_height * (right - left + 1))
9        return max_area

Time: O(nยฒ) โ€” every pair of (left, right) indices is examined once.
Space: O(1) โ€” only a few scalar variables; no extra data structures.

Approach 2 โ€” Monotonic Stack

Maintain a stack of bar indices in strictly increasing order of height. When a bar shorter than the stack top arrives, every taller bar in the stack has found its right boundary โ€” pop and compute area. A sentinel height-0 bar appended to the end forces all remaining bars to be processed.

  1. Append a virtual sentinel bar of height 0 to the end of heights; store as extended.
  2. Maintain a stack of indices; push index 0.
  3. For each index i, while extended[stack[-1]] > extended[i], pop p:
    • bar_height = extended[p]
    • width = i if stack is empty, else i - stack[-1] - 1
    • Update max_area.
  4. Push i.
  5. Return max_area.
1class Solution:
2    def largestRectangleArea(self, heights: list[int]) -> int:
3        extended = heights + [0]  # sentinel forces all remaining candidates off the stack
4        stack: list[int] = []    # indices; heights at these indices are strictly increasing
5        max_area = 0
6
7        for i, current_height in enumerate(extended):
8            while stack and extended[stack[-1]] > current_height:
9                bar_height = extended[stack.pop()]
10                # left boundary is the new stack top (exclusive); right boundary is i (exclusive)
11                width = i if not stack else i - stack[-1] - 1
12                max_area = max(max_area, bar_height * width)
13            stack.append(i)
14
15        return max_area

Time: O(n) โ€” each bar is pushed and popped at most once, so the total work across all iterations is O(n).
Space: O(n) โ€” the stack holds at most n indices in the worst case (a strictly increasing histogram).

Complexity Summary

ApproachTimeSpaceWhen to use
Brute ForceO(nยฒ)O(1)Tiny inputs or when code clarity outweighs performance
Monotonic StackO(n)O(n)Any real workload; this is the expected interview answer

Common Mistakes

  • Miscomputing the width when the stack is non-empty โ€” after popping index p, the left boundary is stack[-1] (the new top), not p - 1. The popped bar may have been preceded by taller bars that were already popped earlier, leaving a gap. The formula i - stack[-1] - 1 accounts for this gap correctly.
  • Forgetting the sentinel โ€” without a height-0 element at the end, bars that are never "beaten" by a shorter bar stay on the stack and are silently ignored. Always process the extra sentinel or loop to n with a virtual height of 0.
  • Confusing stack.top() with the popped bar's left neighbor โ€” after popping p, the new stack top is the exclusive left wall, not p's own left neighbor in the array.
  • Accessing heights[stack[-1]] when the stack might hold the sentinel index โ€” if you push the sentinel index n onto the stack and then try to access heights[n] in a later while-loop condition, you will read out of bounds. Guard with i < n when accessing the original array or use the extended copy throughout.
  • Using the Java remove(Object) overload instead of remove(int) โ€” list.remove(heights[p]) removes the first element equal to heights[p], not the last element; always call list.remove(list.size() - 1) to pop by index.

Related Problems

  • maximal-rectangle โ€” applies this exact histogram algorithm row by row to a 2D binary matrix
  • trapping-rain-water โ€” same monotonic-stack intuition but computing water trapped between bars instead of rectangle area
  • daily-temperatures โ€” textbook monotonic-stack problem: for each day, find the next warmer day
  • sliding-window-maximum โ€” monotonic deque variant that tracks maximums over a sliding window
  • sum-of-subarray-minimums โ€” computes how many subarrays each bar is the minimum of, the same left/right boundary reasoning as the histogram

Ready to practice? Try it on SkillFlow

Adaptive problems, AI follow-up interviews, and a skill score that shows exactly where you need to improve.

Practice This Problem โ†’