Monotonic Stacks & Queues – The Sliding Window Buff

Faiaz KhanFaiaz Khan
4 min read

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

MistakeWhy It HurtsFix
Using values instead of indicesYou can't track position/windowAlways store indices
Forgetting to remove old elementsQueue grows too large or gives wrong resultsPurge anything outside window (i - k)
Wrong stack directionStack grows opposite to what’s neededDefine if you're maintaining increasing or decreasing

Real Life-ish Examples

ScenarioMonotonic Use
Stock SpanTrack previous days where price was higher
Temperature Prediction“How many days until it gets warmer?” = Monotonic Stack
Queueing system with prioritiesMonotonic Queue tracks top priorities
UI Scroll InteractionsDebounce 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 nowhere

  • Clean 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 💪

0
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.