Monotonic Stacks & Queues – The Sliding Window Buff


Ever written a nested loop, stared at your O(n²)
time, and whispered “there has to be a better way”?
There is. And it’s 🔥.
Monotonic Stacks and Queues are those underdog tricks that seem obscure... until they make your entire codebase faster and prettier.
Today, we:
Expose what they really are
Show how to crush sliding window & range problems
Convert brute force into elegance
And drop some common dev pain-points + solutions
What is a Monotonic Stack/Queue?
It’s just a regular stack or queue that maintains a monotonic (increasing or decreasing) order.
Monotonic Stack → Push/pop elements in a way that the values always go up or down.
Monotonic Queue → Same idea, but designed for windowed problems (like max in a sliding window)
It’s not scary — it’s just a data structure with self-respect.
Real-World Intuition
Imagine you’re in a line at a food truck.
But this line only allows people taller than the last person, because we want to easily see the tallest one without looking behind.
Congrats — you’ve just implemented a monotonic decreasing queue.
Use Case 1: Next Greater Element
Problem:
For each element, find the next element that is greater than it.
Brute force:
Nested loop = O(n²)
Monotonic Stack:
function nextGreater(nums) {
const res = Array(nums.length).fill(-1);
const stack = [];
for (let i = nums.length - 1; i >= 0; i--) {
while (stack.length && stack[stack.length - 1] <= nums[i]) {
stack.pop();
}
if (stack.length) res[i] = stack[stack.length - 1];
stack.push(nums[i]);
}
return res;
}
Time complexity: O(n)
Every element is pushed and popped at most once.
Smooth, efficient, and no drama.
Use Case 2: Sliding Window Maximum
Problem:
Find the maximum in every window of size k
.
Brute force:
Slide the window, find max every time = O(nk)
Monotonic Queue:
function maxSlidingWindow(nums, k) {
const res = [];
const deque = []; // stores indices
for (let i = 0; i < nums.length; i++) {
// remove indices out of window
if (deque.length && deque[0] <= i - k) deque.shift();
// remove smaller elements from back
while (deque.length && nums[deque[deque.length - 1]] < nums[i]) {
deque.pop();
}
deque.push(i);
if (i >= k - 1) res.push(nums[deque[0]]);
}
return res;
}
Time Complexity?
O(n). And it feels good.
Use Case 3: Largest Rectangle in Histogram
“Find the largest area of rectangle that fits in a histogram”
This problem?
Monotonic Stack Hell Mode unlocked.
function largestRectangle(heights) {
heights.push(0); // add dummy height
const stack = [-1];
let maxArea = 0;
for (let i = 0; i < heights.length; i++) {
while (stack.length > 1 && heights[i] < heights[stack[stack.length - 1]]) {
const height = heights[stack.pop()];
const width = i - stack[stack.length - 1] - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
This is like LeetCode’s final boss battle with stacks.
And you just critical-hit it with monotonic finesse
Common Mistakes Devs Make
Mistake | Why It Hurts | Fix |
Using values instead of indices | You can't track position/window | Always store indices |
Forgetting to remove old elements | Queue grows too large or gives wrong results | Purge anything outside window (i - k ) |
Wrong stack direction | Stack grows opposite to what’s needed | Define if you're maintaining increasing or decreasing |
Real Life-ish Examples
Scenario | Monotonic Use |
Stock Span | Track previous days where price was higher |
Temperature Prediction | “How many days until it gets warmer?” = Monotonic Stack |
Queueing system with priorities | Monotonic Queue tracks top priorities |
UI Scroll Interactions | Debounce scroll events, track max visible content — fancy apps, fancy data |
Final Thoughts
Monotonic Stacks and Queues are like the ninjas of DSA.
They:
Move in silence
Make your code
O(n)
out of nowhereClean up messy logic
Save you from brute force burnout
If you’re ever staring at nested loops...
Ask yourself: can this be handled by a clean, disrespectfully efficient stack?
📚 This was Code Like You Mean It – DSA Edition,
Where we respect your time complexity and your developer dignity.
Next up:
Who knows. Maybe...
Trie Hard – Efficient Prefix Lookups and Search
or
Union-Find – Breaking Up Is Efficient to Do
Let’s keep it creative, let’s keep it smart, and let’s keep O(n) energy going 💪
Subscribe to my newsletter
Read articles from Faiaz Khan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Faiaz Khan
Faiaz Khan
Hey! I'm Faiaz — a frontend developer who loves writing clean, efficient, and readable code (and sometimes slightly chaotic code, but only when debugging). This blog is my little corner of the internet where I share what I learn about React, JavaScript, modern web tools, and building better user experiences. When I'm not coding, I'm probably refactoring my to-do list or explaining closures to my cat. Thanks for stopping by — hope you find something useful or mildly entertaining here.