Monotonic Stack Introduction
Monotonic Stack Introduction
A monotonic stack is a stack that maintains elements in either strictly increasing or strictly decreasing order.
Types
- Monotonic Decreasing: Top is smallest element
- Monotonic Increasing: Top is largest element
Why It Works
When we encounter an element that violates the monotonic property, we pop elements and process them. Each element is pushed and popped at most once.
Time Complexity
O(n) - each element is pushed and popped at most once.
When to Use
- Next greater element
- Next smaller element
- Largest rectangle in histogram
- Daily temperatures
- Stock span problem
Monotonic Stack Problems
Monotonic Stack Problems
1. Next Greater Element (LeetCode 496)
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer, Integer> map = new HashMap<>();
Deque<Integer> stack = new ArrayDeque<>();
for (int num : nums2) {
while (!stack.isEmpty() && stack.peek() < num) {
map.put(stack.pop(), num);
}
stack.push(num);
}
int[] result = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
result[i] = map.getOrDefault(nums1[i], -1);
}
return result;
}
// Time: O(n), Space: O(n)
2. Daily Temperatures (LeetCode 739)
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] result = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && temperatures[stack.peek()] < temperatures[i]) {
int prevIndex = stack.pop();
result[prevIndex] = i - prevIndex;
}
stack.push(i);
}
return result;
}
// Time: O(n), Space: O(n)
3. Largest Rectangle in Histogram (LeetCode 84)
public int largestRectangleArea(int[] heights) {
Deque<Integer> stack = new ArrayDeque<>();
int maxArea = 0;
int n = heights.length;
for (int i = 0; i <= n; i++) {
int currentHeight = (i == n) ? 0 : heights[i];
while (!stack.isEmpty() && heights[stack.peek()] > currentHeight) {
int height = heights[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
Template
// Next Greater Element (Decreasing Stack)
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
int index = stack.pop();
result[index] = i; // or arr[i]
}
stack.push(i);
}
// Next Smaller Element (Increasing Stack)
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
int index = stack.pop();
result[index] = i; // or arr[i]
}
stack.push(i);
}
Practice Problems
Given an array of temperatures, return an array answer where answer[i] is the number of days you have to wait to get a warmer temperature.
Example:
Input: temperatures = [73,74,75,71,69,72,76,73]
Output: [1,1,4,2,1,1,0,0]
Wait 1 day for 74, 4 days for 76, etc.
Optimal Solution — O(n) time, O(n) space
Monotonic decreasing stack
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] result = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && temperatures[stack.peek()] < temperatures[i]) {
int prev = stack.pop();
result[prev] = i - prev;
}
stack.push(i);
}
return result;
}
}Edge Cases:
- All same temperatures
- Strictly increasing
- Strictly decreasing
Given a circular integer array nums, return the next greater number for every element.
Example:
Input: nums = [1,2,1]
Output: [2,-1,2]
Circular array: next greater of last element is 2.
Optimal Solution — O(n) time, O(n) space
Monotonic stack with circular traversal
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] result = new int[n];
Arrays.fill(result, -1);
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < 2 * n; i++) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i % n]) {
result[stack.pop()] = nums[i % n];
}
if (i < n) stack.push(i);
}
return result;
}
}Edge Cases:
- Single element
- All same
- No next greater
Design a StockSpanner class that calculates the span of stock prices. The span is the maximum number of consecutive days for which the price was less than or equal to today's price.
Example:
Input: StockSpanner s = new StockSpanner(); s.next(100); s.next(80); s.next(60); s.next(70); s.next(60); s.next(75); s.next(85);
Output: [1,1,1,2,1,4,6]
Span of 85 is 6 (days 75,60,70,60,80,100 <= 85).
Optimal Solution — Amortized O(1) time, O(n) space
Monotonic stack storing prices and spans
class StockSpanner {
Deque<int[]> stack; // [price, span]
public StockSpanner() {
stack = new ArrayDeque<>();
}
public int next(int price) {
int span = 1;
while (!stack.isEmpty() && stack.peek()[0] <= price) {
span += stack.pop()[1];
}
stack.push(new int[]{price, span});
return span;
}
}Edge Cases:
- Strictly increasing
- Strictly decreasing
- All same price
Quiz
1. What is the time complexity of monotonic stack solutions?
2. For next greater element, which stack direction do we use?
3. What is the primary purpose of Monotonic Stack?
4. What is a common mistake when implementing Monotonic Stack?
Flashcards
Question
What is a monotonic stack?
Click to reveal answer
Answer
A stack that maintains elements in strictly increasing or decreasing order.
Question
When to use monotonic stack?
Click to reveal answer
Answer
For next greater/smaller element problems, and histogram problems.
Question
What is Monotonic Stack?
Click to reveal answer
Answer
Monotonic Stack is a key concept in software engineering.
Question
When to use Monotonic Stack?
Click to reveal answer
Answer
Use Monotonic Stack when building production systems that require reliability, scalability, and maintainability.
Question
Monotonic Stack best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Monotonic stack maintains order
- 2.Each element processed exactly once
- 3.Use for next greater/smaller problems
- 4.Template pattern is reusable
Interview Tips
- •Identify if problem needs next greater/smaller
- •Draw the stack evolution
- •Explain why O(n) is optimal
Cheat Sheet
Monotonic Stack Cheat Sheet
Decreasing Stack: For next greater element
Increasing Stack: For next smaller element
Time: O(n) - each element pushed/popped once
Pattern: Pop while condition violated, push current