Largest Rectangle in Histogram Using Stack in DSA C# - Time & Space Complexity
We want to understand how the time needed to find the largest rectangle in a histogram changes as the number of bars grows.
How does the algorithm's work increase when the histogram gets bigger?
Analyze the time complexity of the following code snippet.
public int LargestRectangleArea(int[] heights) {
Stack<int> stack = new Stack<int>();
int maxArea = 0;
for (int i = 0; i <= heights.Length; i++) {
int h = (i == heights.Length) ? 0 : heights[i];
while (stack.Count > 0 && h < heights[stack.Peek()]) {
int height = heights[stack.Pop()];
int width = stack.Count == 0 ? i : i - stack.Peek() - 1;
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 runs through all bars once, and inside it, bars are pushed and popped from the stack.
- How many times: Each bar is pushed once and popped once, so stack operations happen at most 2n times for n bars.
As the number of bars (n) increases, the total operations grow roughly in a straight line with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 stack operations |
| 100 | About 200 stack operations |
| 1000 | About 2000 stack operations |
Pattern observation: The operations grow linearly, doubling the bars roughly doubles the work.
Time Complexity: O(n)
This means the time to find the largest rectangle grows directly in proportion to the number of bars.
[X] Wrong: "Because there is a nested while loop inside the for loop, the time complexity must be O(n²)."
[OK] Correct: Each bar is pushed and popped only once, so the inner loop does not run for every iteration fully, keeping total operations linear.
Understanding this linear time solution shows you can use stacks smartly to solve problems efficiently, a skill valued in many coding challenges.
"What if we used a simple nested loop to check all rectangles instead of a stack? How would the time complexity change?"
Practice
Solution
Step 1: Understand stack usage in the problem
The stack stores indices of bars in increasing order of their heights to help calculate areas efficiently.Step 2: Why store indices, not heights?
Indices allow calculation of width between bars when popping from the stack, which is essential for area calculation.Final Answer:
To keep track of bars' indices with increasing heights -> Option AQuick Check:
Stack stores indices for area calculation [OK]
- Storing heights instead of indices
- Using stack to sort bars
- Ignoring width calculation using indices
Solution
Step 1: Identify correct stack initialization in C#
Using generic Stack<int> is the modern and type-safe way to create a stack for integers.Step 2: Why not others?
The non-generic Stack (like "Stack stack = new Stack();") uses the older style without type safety. A List (like "List<int> stack = new List<int>();") is not a stack. An array (like "int[] stack = new int[10];") is not a stack.Final Answer:
Stack<int> stack = new Stack<int>(); -> Option DQuick Check:
Generic Stack<int> is correct stack initialization [OK]
- Using non-generic Stack without type safety
- Using List instead of Stack
- Using arrays instead of stack
int[] heights = {2, 1, 5, 6, 2, 3};
int largestRectangleArea(int[] heights) {
Stack<int> stack = new Stack<int>();
int maxArea = 0, i = 0;
while (i < heights.Length) {
if (stack.Count == 0 || heights[i] >= heights[stack.Peek()]) {
stack.Push(i++);
} else {
int top = stack.Pop();
int width = stack.Count == 0 ? i : i - stack.Peek() - 1;
maxArea = Math.Max(maxArea, heights[top] * width);
}
}
while (stack.Count > 0) {
int top = stack.Pop();
int width = stack.Count == 0 ? i : i - stack.Peek() - 1;
maxArea = Math.Max(maxArea, heights[top] * width);
}
return maxArea;
}
Console.WriteLine(largestRectangleArea(heights));Solution
Step 1: Trace the stack operations and area calculations
For heights [2,1,5,6,2,3], the largest rectangle area is 10 (from bars 5 and 6 with width 2).Step 2: Confirm final maxArea
After processing all bars and stack cleanup, maxArea is 10.Final Answer:
10 -> Option BQuick Check:
Largest rectangle area = 10 [OK]
- Miscomputing width when popping stack
- Forgetting to process remaining stack after loop
- Mixing up indices and heights
int largestRectangleArea(int[] heights) {
Stack<int> stack = new Stack<int>();
int maxArea = 0, i = 0;
while (i <= heights.Length) {
int currentHeight = (i == heights.Length) ? 0 : heights[i];
if (stack.Count == 0 || currentHeight >= heights[stack.Peek()]) {
stack.Push(i++);
} else {
int top = stack.Pop();
int width = stack.Count == 0 ? i : i - stack.Peek() - 1;
maxArea = Math.Max(maxArea, heights[top] * width);
}
}
return maxArea;
}Solution
Step 1: Check width calculation formula
Width should be i - stack.Peek() - 1 when stack is not empty, but code misses '-1'.Step 2: Effect of missing '-1'
Missing '-1' causes width to be larger than actual, leading to incorrect maxArea.Final Answer:
Width calculation misses subtracting 1, causing wrong area -> Option AQuick Check:
Width must subtract 1 for correct area [OK]
- Forgetting to subtract 1 in width
- Using stack for heights instead of indices
- Incorrect loop boundary causing index errors
Solution
Step 1: Use stack to track indices of increasing heights
Push indices while heights increase; pop when current height is less, calculating area with popped height and width between indices.Step 2: Calculate largest area for given heights
For [6,2,5,4,5,1,6], largest rectangle area is 12 (from bars at indices 2,3,4 with min height 4 and width 3, calculated when popping index 3).Final Answer:
12 -> Option CQuick Check:
Stack helps find max area = 12 [OK]
- Not popping all remaining bars after loop
- Incorrect width calculation
- Confusing heights and indices in stack
Ready to prove it?
Pass the test and this pattern moves unknown
