Largest Rectangle in Histogram – Solution & Complexity

Solution Walkthrough

  1. Step 1: Understanding the Problem

    • Each bar has width 1 and a given height.
    • A rectangle spans a contiguous range of bars and its height is the shortest bar in that range.
    • We want the maximum possible height * width over all ranges.
  2. Step 2: The Key Insight

    • For each bar, imagine it is the limiting (shortest) bar of a rectangle.
    • That rectangle stretches left and right until it meets a strictly shorter bar.
    • If we know those left/right boundaries for every bar, the area is height * (right - left - 1).
  3. Step 3: Using a Monotonic Stack

    • Keep a stack of bar indices whose heights are increasing.
    • When the current bar is shorter than the bar on top of the stack, that top bar's rectangle must end here.
    • Pop it, compute its area, and repeat until the stack is increasing again.
    def largest_rectangle_area(heights):
        stack = []  # indices of increasing bars
        best = 0
        for i, h in enumerate(heights):
            while stack and heights[stack[-1]] > h:
                height = heights[stack.pop()]
                width = i if not stack else i - stack[-1] - 1
                best = max(best, height * width)
            stack.append(i)
        n = len(heights)
        while stack:
            height = heights[stack.pop()]
            width = n if not stack else n - stack[-1] - 1
            best = max(best, height * width)
        return best
  4. Step 4: Draining the Stack with a Sentinel

    • After the loop, bars still on the stack never met a shorter bar to their right.
    • Appending a sentinel height of 0 forces every remaining bar to be popped and measured.
    • The width uses the array length as the right boundary.
    def largest_rectangle_area(heights):
        stack = []
        best = 0
        for i, h in enumerate(heights + [0]):  # sentinel flushes the stack
            while stack and heights[stack[-1]] >= h:
                height = heights[stack.pop()]
                width = i if not stack else i - stack[-1] - 1
                best = max(best, height * width)
            stack.append(i)
        return best
  5. Step 5: Complexity

    • Time: O(n) because each bar is pushed and popped exactly once.
    • Space: O(n) for the stack.

FAQ