Largest Rectangle in Histogram
Monotonic increasing stack — at every pop, the popped bar's rectangle spans from previous stack top to current index.
3 min read
monotonic-stack array
Problem#
Given bar heights, return the area of the largest axis-aligned rectangle entirely inside the histogram.
Examples#
[2,1,5,6,2,3]→10.[2,4]→4.
Constraints#
1 <= heights.length <= 10^5,0 <= heights[i] <= 10^4.
Approach#
Monotonic increasing stack of indices. For each new bar, pop bars taller than it; for each popped bar, its rectangle’s width is i - (stack.top() after pop) - 1. Append a sentinel 0 to flush remaining bars.
Solution#
class Solution {public: int largestRectangleArea(vector<int>& h) { h.push_back(0); stack<int> st; int best = 0; for (int i = 0; i < (int)h.size(); ++i) { while (!st.empty() && h[st.top()] > h[i]) { int top = st.top(); st.pop(); int width = st.empty() ? i : (i - st.top() - 1); best = max(best, h[top] * width); } st.push(i); } h.pop_back(); return best; }};func largestRectangleArea(h []int) int { h = append(h, 0) st := []int{} best := 0 for i := 0; i < len(h); i++ { for len(st) > 0 && h[st[len(st)-1]] > h[i] { top := st[len(st)-1] st = st[:len(st)-1] width := i if len(st) > 0 { width = i - st[len(st)-1] - 1 } if area := h[top] * width; area > best { best = area } } st = append(st, i) } return best}from typing import List
class Solution: def largestRectangleArea(self, h: List[int]) -> int: h.append(0) st: List[int] = [] best = 0 for i in range(len(h)): while st and h[st[-1]] > h[i]: top = st.pop() width = i if not st else i - st[-1] - 1 best = max(best, h[top] * width) st.append(i) h.pop() return bestfunction largestRectangleArea(h) { h.push(0); const st = []; let best = 0; for (let i = 0; i < h.length; i++) { while (st.length > 0 && h[st[st.length - 1]] > h[i]) { const top = st.pop(); const width = st.length === 0 ? i : i - st[st.length - 1] - 1; best = Math.max(best, h[top] * width); } st.push(i); } h.pop(); return best;}class Solution { public int largestRectangleArea(int[] heights) { int n = heights.length; int[] h = new int[n + 1]; System.arraycopy(heights, 0, h, 0, n); h[n] = 0; Deque<Integer> st = new ArrayDeque<>(); int best = 0; for (int i = 0; i < h.length; i++) { while (!st.isEmpty() && h[st.peek()] > h[i]) { int top = st.pop(); int width = st.isEmpty() ? i : (i - st.peek() - 1); best = Math.max(best, h[top] * width); } st.push(i); } return best; }}function largestRectangleArea(h: number[]): number { h.push(0); const st: number[] = []; let best = 0; for (let i = 0; i < h.length; i++) { while (st.length > 0 && h[st[st.length - 1]] > h[i]) { const top = st.pop() as number; const width = st.length === 0 ? i : i - st[st.length - 1] - 1; best = Math.max(best, h[top] * width); } st.push(i); } h.pop(); return best;}Editorial#
The stack stores increasing-height bar indices. When a shorter bar arrives, every taller bar in the stack has found its right boundary (the new bar) — and its left boundary is the previous stack element after popping. Each bar is pushed and popped at most once: O(n).
Complexity#
- Time:
O(n). - Space:
O(n).
Concept revision#
Related#