Largest Rectangle in Histogram Using Stack in DSA Typescript - Time & Space Complexity
We want to know how the time needed to find the largest rectangle in a histogram changes as the number of bars grows.
How does the stack-based method handle more bars efficiently?
Analyze the time complexity of the following code snippet.
function largestRectangleArea(heights: number[]): number {
const stack: number[] = [];
let maxArea = 0;
for (let i = 0; i <= heights.length; i++) {
const currentHeight = i === heights.length ? 0 : heights[i];
while (stack.length && currentHeight < heights[stack[stack.length - 1]]) {
const height = heights[stack.pop()!];
const width = stack.length ? i - stack[stack.length - 1] - 1 : i;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
This code finds the largest rectangle area in a histogram by using a stack to track bars and calculate areas efficiently.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop through all bars plus stack push/pop operations.
- How many times: Each bar is pushed and popped at most once, so operations happen roughly 2n times for n bars.
As the number of bars increases, the total operations grow roughly twice the number of bars because each bar is pushed and popped once.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 stack operations |
| 100 | About 200 stack operations |
| 1000 | About 2000 stack operations |
Pattern observation: Operations grow linearly with input size, doubling roughly because of push and pop per bar.
Time Complexity: O(n)
This means the time to find the largest rectangle grows in direct proportion to the number of bars.
[X] Wrong: "Because of the nested while loop inside the for loop, the time complexity is O(n²)."
[OK] Correct: Each bar is pushed and popped only once, so the inner loop does not run n times for each iteration, keeping total operations linear.
Understanding this stack approach shows you can use clever data structures to reduce what looks like a complex problem into a fast, simple solution.
"What if we used a simple nested loop to check every possible rectangle instead of a stack? How would the time complexity change?"
Practice
Solution
Step 1: Understand the stack's role
The stack stores indices of bars in increasing height order to find boundaries for rectangles.Step 2: Why increasing heights?
This helps identify when a bar is lower than the previous, signaling to calculate area for taller bars.Final Answer:
To keep track of bars' indices with increasing heights -> Option BQuick Check:
Stack tracks increasing bars = To keep track of bars' indices with increasing heights [OK]
- Thinking stack sorts bars by height
- Using stack to store areas instead of indices
- Ignoring the order of bars in the stack
Solution
Step 1: Identify correct stack type
We need a stack of numbers (indices), so number[] is correct.Step 2: Check other options
const stack: string[] = []; uses string[], wrong type. const stack = new Stack<number>(); uses a Stack class which is not standard in TypeScript. const stack = []; stack.push('index'); pushes a string 'index', wrong type.Final Answer:
const stack: number[] = []; -> Option CQuick Check:
Stack of numbers = const stack: number[] = []; [OK]
- Using string[] instead of number[]
- Assuming Stack class exists by default
- Pushing wrong data types into stack
function largestRectangleArea(heights: number[]): number {
const stack: number[] = [];
let maxArea = 0;
heights.push(0);
for (let i = 0; i < heights.length; i++) {
while (stack.length && heights[i] < heights[stack[stack.length - 1]]) {
const height = heights[stack.pop()!];
const width = stack.length ? i - stack[stack.length - 1] - 1 : i;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
console.log(largestRectangleArea([2, 1, 5, 6, 2, 3]));Solution
Step 1: Add sentinel and iterate
Heights become [2,1,5,6,2,3,0]. We use stack to track indices of increasing bars.Step 2: Calculate max area during pops
Pop bars when current height is less, calculate area: max area found is 10 (from bars 5 and 6 with width 2).Final Answer:
10 -> Option AQuick Check:
Max rectangle area = 10 [OK]
- Not adding sentinel 0 at end
- Wrong width calculation after popping
- Ignoring last bars in stack
function largestRectangleArea(heights: number[]): number {
const stack: number[] = [];
let maxArea = 0;
for (let i = 0; i <= heights.length; i++) {
while (stack.length && heights[i] < heights[stack[stack.length - 1]]) {
const height = heights[stack.pop()!];
const width = stack.length ? i - stack[stack.length - 1] - 1 : i;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}Solution
Step 1: Check loop boundary
The loop runs i from 0 to heights.length inclusive, so heights[i] is accessed when i == heights.length, causing out-of-bounds error.Step 2: Fix by adding sentinel or changing loop
Adding a 0 height at end or changing loop to i < heights.length fixes this.Final Answer:
Loop goes out of bounds accessing heights[i] when i == heights.length -> Option DQuick Check:
Out-of-bounds access = Loop goes out of bounds accessing heights[i] when i == heights.length [OK]
- Ignoring loop boundary causing runtime error
- Assuming stack initialization is wrong
- Misreading width calculation
Solution
Step 1: Use stack to find max area
Push indices while heights increase. When a lower bar appears, pop and calculate area. For this histogram, max area is 12 from bars at indices 2,3,4 (heights 5,4,5) width 3.Step 2: Why area 12 is largest
The rectangle covers bars with heights >=4 over width 3, area = 4*3=12. No other rectangle covers more area.Final Answer:
12 -> Option AQuick Check:
Max rectangle area = 12 [OK]
- Calculating area only for single bars
- Ignoring width when popping multiple bars
- Missing the largest rectangle spanning multiple bars
Ready to prove it?
Pass the test and this pattern moves unknown
