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 1:
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.
Example 2:
Input: heights = [2,4]
Output: 4
Constraints:
1 <= heights.length <= 105
0 <= heights[i] <= 104
Solutions
Solution 1: Monotonic Stack
Thinking
The first idea is enumerate every interval \([l, r]\), take the min height, area \((r - l + 1) \times \min\). Correct, but \(O(n^2)\). \(n \le 10^5\) will time out.
The bottleneck is recomputing the min over every range. Flip the enumeration: let bar \(i\) be the shortest bar of the rectangle; the width is the span to the nearest strictly shorter bars on both sides.
“Nearest smaller on left/right” is the monotonic-stack model. Indices in the stack have increasing heights; a shorter bar pops others and becomes their right bound, while the new top is the left bound. Each bar enters and leaves once, so one linear pass.
We can enumerate the height \(h\) of each bar as the height of the rectangle. Using a monotonic stack, we find the index \(left_i\), \(right_i\) of the first bar with a height less than \(h\) to the left and right. The area of the rectangle at this time is \(h \times (right_i-left_i-1)\). We can find the maximum value.
The time complexity is \(O(n)\), and the space complexity is \(O(n)\). Here, \(n\) represents the length of \(heights\).
Common model of monotonic stack: Find the nearest number to the left/right of each number that is larger/smaller than it. Template:
implSolution{#[allow(dead_code)]pubfnlargest_rectangle_area(heights:Vec<i32>)->i32{letn=heights.len();letmutleft=vec![-1;n];letmutright=vec![-1;n];letmutstack:Vec<(usize,i32)>=Vec::new();letmutret=-1;// Build left vectorfor(i,h)inheights.iter().enumerate(){while!stack.is_empty()&&stack.last().unwrap().1>=*h{stack.pop();}ifstack.is_empty(){left[i]=-1;}else{left[i]=stack.last().unwrap().0asi32;}stack.push((i,*h));}stack.clear();// Build right vectorfor(i,h)inheights.iter().enumerate().rev(){while!stack.is_empty()&&stack.last().unwrap().1>=*h{stack.pop();}ifstack.is_empty(){right[i]=nasi32;}else{right[i]=stack.last().unwrap().0asi32;}stack.push((i,*h));}// Calculate the max areafor(i,h)inheights.iter().enumerate(){ret=std::cmp::max(ret,(right[i]-left[i]-1)**h);}ret}}