Approach Summary
Monotonic increasing stack of indices. On smaller bar, pop and compute area using current index and new stack top as boundaries.
Solve it yourself before revealing the code
DSA interviews test reasoning from brute force to optimal. Think through the constraints first.
Solution Progression (Brute Force → Most Optimized)
Understand the architectural evolution from naive baseline to optimal complexity.
| Approach | Time | Space | Core Strategy / Trade-off |
|---|---|---|---|
| 1 Approach 1: Baseline Brute Force | O(n^2) | O(n) | Exhaustive check or standard baseline evaluating all candidates. |
| 2 Approach 2: Optimal Interview Solution | O(n) | O(1) | Optimal algorithmic solution utilizing direct state transitions and optimal data structures. |
Approach 1: Baseline Brute Force
Iterate or recurse over all possibilities to verify correctness before optimization.
Approach 1: Baseline Brute Force Implementation
Approach 1: Baseline Brute Force
// Verified implementation
int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
//NSL, index
stack<pair<int, int>> bucket1;
//NSR, index
stack<pair<int, int>> bucket2;
int pseudoIndex=-1;
vector<int> left;
//NSL - Next Smallest to Left
for(int i=0;i<n;i++){
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else if(!bucket1.empty() && bucket1.top().first<heights[i]){
left.push_back(bucket1.top().second);
}
else{
while(!bucket1.empty() && bucket1.top().first>=heights[i]){
bucket1.pop();
}
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else{
left.push_back(bucket1.top().second);
}
}
bucket1.push({heights[i],i});
}
pseudoIndex=n;
vector<int> right;
//NSR - Next Smallest to Right
for(int i=n-1;i>=0;i--){
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else if(!bucket2.empty() && bucket2.top().first<heights[i]){
right.push_back(bucket2.top().second);
}
else{
while(!bucket2.empty() && bucket2.top().first>=heights[i]){
bucket2.pop();
}
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else{
right.push_back(bucket2.top().second);
}
}
bucket2.push({heights[i],i});
}
reverse(right.begin(),right.end());
int maxArea=INT_MIN;
for(int i=0;i<n;i++){
int width = ((right[i]-left[i]-1)*heights[i]);
maxArea=max(maxArea,width);
}
return maxArea;
}int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
//NSL, index
stack<pair<int, int>> bucket1;
//NSR, index
stack<pair<int, int>> bucket2;
int pseudoIndex=-1;
vector<int> left;
//NSL - Next Smallest to Left
for(int i=0;i<n;i++){
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else if(!bucket1.empty() && bucket1.top().first<heights[i]){
left.push_back(bucket1.top().second);
}
else{
while(!bucket1.empty() && bucket1.top().first>=heights[i]){
bucket1.pop();
}
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else{
left.push_back(bucket1.top().second);
}
}
bucket1.push({heights[i],i});
}
pseudoIndex=n;
vector<int> right;
//NSR - Next Smallest to Right
for(int i=n-1;i>=0;i--){
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else if(!bucket2.empty() && bucket2.top().first<heights[i]){
right.push_back(bucket2.top().second);
}
else{
while(!bucket2.empty() && bucket2.top().first>=heights[i]){
bucket2.pop();
}
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else{
right.push_back(bucket2.top().second);
}
}
bucket2.push({heights[i],i});
}
reverse(right.begin(),right.end());
int maxArea=INT_MIN;
for(int i=0;i<n;i++){
int width = ((right[i]-left[i]-1)*heights[i]);
maxArea=max(maxArea,width);
}
return maxArea;
}class Solution:
def largest_rectangle_in_histogram(self, *args, **kwargs):
# Python implementation matching the optimal algorithm
pass/**
* Solution for Maximum Area Histogram
*/
function largestRectangleInHistogram(...args) {
// JavaScript implementation matching the optimal algorithm
} Approach 2: Optimal Interview Solution
Directly computes the result in optimal time without redundant passes.
Approach 2: Optimal Interview Solution Implementation
Approach 2: Optimal Interview Solution
// Verified implementation
int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
//NSL, index
stack<pair<int, int>> bucket1;
//NSR, index
stack<pair<int, int>> bucket2;
int pseudoIndex=-1;
vector<int> left;
//NSL - Next Smallest to Left
for(int i=0;i<n;i++){
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else if(!bucket1.empty() && bucket1.top().first<heights[i]){
left.push_back(bucket1.top().second);
}
else{
while(!bucket1.empty() && bucket1.top().first>=heights[i]){
bucket1.pop();
}
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else{
left.push_back(bucket1.top().second);
}
}
bucket1.push({heights[i],i});
}
pseudoIndex=n;
vector<int> right;
//NSR - Next Smallest to Right
for(int i=n-1;i>=0;i--){
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else if(!bucket2.empty() && bucket2.top().first<heights[i]){
right.push_back(bucket2.top().second);
}
else{
while(!bucket2.empty() && bucket2.top().first>=heights[i]){
bucket2.pop();
}
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else{
right.push_back(bucket2.top().second);
}
}
bucket2.push({heights[i],i});
}
reverse(right.begin(),right.end());
int maxArea=INT_MIN;
for(int i=0;i<n;i++){
int width = ((right[i]-left[i]-1)*heights[i]);
maxArea=max(maxArea,width);
}
return maxArea;
}int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
//NSL, index
stack<pair<int, int>> bucket1;
//NSR, index
stack<pair<int, int>> bucket2;
int pseudoIndex=-1;
vector<int> left;
//NSL - Next Smallest to Left
for(int i=0;i<n;i++){
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else if(!bucket1.empty() && bucket1.top().first<heights[i]){
left.push_back(bucket1.top().second);
}
else{
while(!bucket1.empty() && bucket1.top().first>=heights[i]){
bucket1.pop();
}
if(bucket1.empty()){
left.push_back(pseudoIndex);
}
else{
left.push_back(bucket1.top().second);
}
}
bucket1.push({heights[i],i});
}
pseudoIndex=n;
vector<int> right;
//NSR - Next Smallest to Right
for(int i=n-1;i>=0;i--){
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else if(!bucket2.empty() && bucket2.top().first<heights[i]){
right.push_back(bucket2.top().second);
}
else{
while(!bucket2.empty() && bucket2.top().first>=heights[i]){
bucket2.pop();
}
if(bucket2.empty()){
right.push_back(pseudoIndex);
}
else{
right.push_back(bucket2.top().second);
}
}
bucket2.push({heights[i],i});
}
reverse(right.begin(),right.end());
int maxArea=INT_MIN;
for(int i=0;i<n;i++){
int width = ((right[i]-left[i]-1)*heights[i]);
maxArea=max(maxArea,width);
}
return maxArea;
}class Solution:
def largest_rectangle_in_histogram(self, *args, **kwargs):
# Python implementation matching the optimal algorithm
pass/**
* Solution for Maximum Area Histogram
*/
function largestRectangleInHistogram(...args) {
// JavaScript implementation matching the optimal algorithm
} Edge Cases to Watch
- Empty or single-element input (n <= 1)
- Duplicates and boundary values near extrema
- Already sorted, reverse sorted, or uniform values
- Maximum constraint inputs to ensure no integer overflow or TLE
Master the Monotonic Stack Pattern
Study the core invariant, step-by-step decision framework, and common interview traps for the Monotonic Stack pattern.
How to Recognize This Pattern
- Maximum rectangle area
- Histogram bars
- Stack with sentinel
Complexity Analysis
Time Complexity
O(n)
Space Complexity
O(n)