Leetcode 84. Largest Rectangle in Histogram

10 January 2026
8 min read

Problem Description

Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.

Example

Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.

Solution Approach

Key Insight

The key insight is that for each bar, we want to find:

1. Next Smaller Element (NSE): The first bar to the right that is smaller than the current bar

2. Previous Smaller Element (PSE): The first bar to the left that is smaller than the current bar

Once we know these boundaries, the width of the rectangle that can be formed with the current bar as the height is:

width = (nextSmallerIndex - 1) - (previousSmallerIndex + 1) + 1
      = nextSmallerIndex - previousSmallerIndex - 1

The area would be: width * heights[i]

Why Monotonic Stack?

This problem is a perfect application of monotonic stacks:

  • We need to find the next/previous smaller element efficiently
  • A naive O(n²) approach would check every bar for each bar
  • Monotonic stacks allow us to find these boundaries in O(n) time
  • Thought Process

    1. Find Next Smaller Element (NSE):

    - Use a monotonic increasing stack (larger elements on top)

    - Iterate from right to left

    - For each bar, pop all bars that are >= current bar

    - The top of the stack (if exists) is the next smaller element to the right

    2. Find Previous Smaller Element (PSE):

    - Use a monotonic increasing stack

    - Iterate from left to right

    - For each bar, pop all bars that are >= current bar

    - The top of the stack (if exists) is the previous smaller element to the left

    3. Calculate Maximum Area:

    - For each bar, calculate the rectangle area using the boundaries found

    - Track the maximum area

    Code Solution

    python
    class Solution:
        def largestRectangleArea(self, heights: List[int]) -> int:
            n = len(heights)
            ns = [n]*n  # next smaller index (default to n if none found)
            ps = [-1]*n  # previous smaller index (default to -1 if none found)
            
            # Find next smaller element (right to left)
            stack = []
            for i in range(n-1, -1, -1):
                while stack and heights[stack[-1]] >= heights[i]:
                    stack.pop()
                if stack:
                    ns[i] = stack[-1]
                stack.append(i)
            
            # Find previous smaller element (left to right)
            stack = []
            for i in range(n):
                while stack and heights[stack[-1]] >= heights[i]:
                    stack.pop()
                if stack:
                    ps[i] = stack[-1]
                stack.append(i)
            
            # Calculate maximum area
            ans = 0
            for i in range(n):
                # Width = (nextSmaller - 1) - (previousSmaller + 1) + 1
                #      = nextSmaller - previousSmaller - 1
                cur = (ns[i] - ps[i] - 1) * heights[i]
                ans = max(ans, cur)
            
            return ans

    Detailed Explanation

    Step-by-Step Walkthrough

    Let's trace through the example heights = [2,1,5,6,2,3]:

    Step 1: Find Next Smaller Element (NSE)

    Iterate from right to left with a monotonic increasing stack:

    IndexHeightStack BeforeActionNSE
    53[]Push 56 (default)
    42[5]Pop 5 (3 >= 2), Push 46
    36[4]Push 34
    25[4, 3]Push 23
    11[4, 3, 2]Pop all (all >= 1), Push 16
    02[1]Push 01

    Result: ns = [1, 6, 3, 4, 6, 6]

    Step 2: Find Previous Smaller Element (PSE)

    Iterate from left to right with a monotonic increasing stack:

    IndexHeightStack BeforeActionPSE
    02[]Push 0-1
    11[0]Pop 0 (2 >= 1), Push 1-1
    25[1]Push 21
    36[1, 2]Push 32
    42[1, 2, 3]Pop 3, 2 (6,5 >= 2), Push 41
    53[1, 4]Push 54

    Result: ps = [-1, -1, 1, 2, 1, 4]

    Step 3: Calculate Areas

    IndexHeightNSEPSEWidthArea
    021-11-(-1)-1 = 12×1 = 2
    116-16-(-1)-1 = 61×6 = 6
    25313-1-1 = 15×1 = 5
    36424-2-1 = 16×1 = 6
    42616-1-1 = 42×4 = 10
    53646-4-1 = 13×1 = 3

    Maximum Area: 10

    Why This Works

    1. Monotonic Stack Property: The stack maintains elements in increasing order, allowing us to efficiently find the next/previous smaller element.

    2. Boundary Detection:

    - When we pop an element, it means we've found a smaller element (the current one)

    - The element at the top of the stack (after popping) is the boundary we're looking for

    3. Width Calculation:

    - ns[i] is the first index to the right where height is smaller

    - ps[i] is the first index to the left where height is smaller

    - The rectangle can extend from ps[i] + 1 to ns[i] - 1

    - Width = (ns[i] - 1) - (ps[i] + 1) + 1 = ns[i] - ps[i] - 1

    Time & Space Complexity

  • Time Complexity: O(n)
  • - Each element is pushed and popped from the stack at most once

    - Three passes through the array: O(n) each

  • Space Complexity: O(n)
  • - Stack: O(n) in worst case

    - Arrays for NSE and PSE: O(n) each

    Key Takeaways

    1. Monotonic stacks are perfect for finding next/previous smaller/greater elements

    2. Two-pass approach: Find boundaries first, then calculate areas

    3. Default values matter: Using n for NSE and -1 for PSE handles edge cases where no smaller element exists

    4. Width calculation: width = nextSmallerIndex - previousSmallerIndex - 1

    Related Problems

  • [Next Greater Element I](https://leetcode.com/problems/next-greater-element-i/)
  • [Daily Temperatures](https://leetcode.com/problems/daily-temperatures/)
  • [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/)
  • [Maximal Rectangle](https://leetcode.com/problems/maximal-rectangle/)