Junior 8 min · March 05, 2026

Monotonic Stack Pattern Fixes O(n²) Stock Indexing

30-sec timeout from O(n²) loops on 10k ticks.

N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Declarative structure: maintain sorted order in a stack by popping violations on push
  • Two variants: decreasing (next greater) and increasing (next smaller)
  • Each element pushed and popped at most once → O(n) amortised
  • Real‑world: stock span APIs, histogram area, trapped rainwater
  • Production trap: wrong comparison sign (<= vs <) silently shifts answers
✦ Definition~90s read
What is Monotonic Stack Pattern?

A monotonic stack is a stack that maintains its elements in strictly increasing or decreasing order as you push new items. It solves the problem of finding the next greater (or smaller) element for every item in an array in O(n) time instead of the naive O(n²) brute-force comparison.

Imagine you're standing in a line at a concert, and everyone wants to know: 'Who's the next taller person behind me?' Instead of every person turning around and scanning the whole crowd (slow!), you use a bouncer who maintains a running list — kicking out anyone shorter as taller people arrive.

The core insight is that when you encounter a value that breaks the monotonic property, you pop elements from the stack — and those popped elements have just found their answer. This pattern is essential for problems like stock span, daily temperatures, and largest rectangle in histogram, where you need to efficiently track 'next greater' relationships without nested loops.

In the stock indexing context, the monotonic stack eliminates the need to scan backward for each day's price. As you iterate forward, the stack holds indices of days with decreasing prices. When a higher price appears, you pop all lower-price indices from the stack — each popped index's 'next greater' is the current day.

This single pass gives you the span (consecutive days with lower or equal prices) for every day in O(n) amortised time. The key tradeoff: you sacrifice the ability to answer arbitrary range queries (use a segment tree for that) but gain linear time for the specific 'next greater' pattern.

Real-world implementations appear in financial data pipelines (e.g., calculating rolling volatility windows in QuantLib), ad-tech bid price analysis, and even database query optimizers for range scans. The pattern is not a silver bullet — avoid it when you need arbitrary sliding window statistics or when the array is already sorted (the stack never pops, making it effectively useless).

But for any problem where each element's answer depends on the next element that breaks a monotonic sequence, this is the canonical O(n) solution that senior engineers reach for without hesitation.

Plain-English First

Imagine you're standing in a line at a concert, and everyone wants to know: 'Who's the next taller person behind me?' Instead of every person turning around and scanning the whole crowd (slow!), you use a bouncer who maintains a running list — kicking out anyone shorter as taller people arrive. That bouncer's list is your monotonic stack. It's always sorted, always current, and always answers your question in one pass.

Most developers hit a wall with array problems that demand knowing the 'next greater' or 'previous smaller' element at every index. The naive approach — a nested loop — works on paper but collapses at scale. When you're processing stock prices, rendering bar charts, or evaluating weather forecasts over millions of data points, O(n²) isn't a trade-off; it's a dealbreaker. The monotonic stack pattern is one of those rare tools that turns a quadratic problem into a linear one without any exotic data structure magic — just a regular stack used with discipline.

The core problem it solves is deceptively simple: for each element in an array, find the nearest element to its left or right that is greater or smaller than it. Brute force checks every pair. The monotonic stack makes one observation that changes everything — if you're scanning left-to-right and you encounter an element that 'dominates' the element on top of the stack, the dominated element has found its answer. You process it, pop it, and never look at it again. That amortized O(1) pop-per-element is where the O(n) total time comes from.

By the end of this article you'll be able to implement both monotonically increasing and decreasing stacks from scratch, identify which variant a problem requires, handle tricky edge cases like duplicate values and circular arrays, and explain the amortized time complexity to an interviewer without flinching. You'll also walk away with a mental checklist that maps problem phrasing directly to the right stack orientation — so you stop guessing.

How a Stack Becomes Monotonic and Why That Cuts O(n²) to O(n)

A monotonic stack is a stack whose elements remain in strictly increasing or decreasing order as you push new items. The core mechanic: before pushing a new element, pop all elements that violate the desired order. This single pass over the input, with each element pushed and popped at most once, yields O(n) total time — a direct replacement for nested loops that would cost O(n²).

In practice, you maintain either a monotonic increasing stack (for next smaller element) or monotonic decreasing stack (for next greater element). The key property: when you pop an element, you know the current incoming element is the first element that breaks the monotonic condition for the popped element. This gives you an immediate answer for that popped element's "next" relationship without revisiting it. The stack holds indices, not values, so you can compute distances or retrieve values from the original array.

Use this pattern whenever you need to find the next (or previous) greater or smaller element for every position in an array — stock span, daily temperatures, histogram largest rectangle, or sliding window maximum. In real systems, this replaces O(n²) brute-force indexing with a single linear pass, which matters when processing millions of price ticks or sensor readings per second.

Monotonic ≠ Sorted Input
The stack itself is monotonic, not the input array. You enforce order during traversal — the input can be completely random.
Production Insight
A real-time stock feed processor used nested loops to compute 5-minute price span for 10,000 tickers every second. Latency spiked to 800ms during high volatility, causing missed ticks and stale quotes. The monotonic stack reduced per-ticker processing from O(n²) to O(n), cutting latency to under 5ms and eliminating dropped ticks entirely.
Key Takeaway
Monotonic stack reduces nested-loop problems to O(n) by exploiting order relationships.
Each element is pushed and popped exactly once — the total work is linear in input size.
Always store indices, not values, to retain positional context for distance calculations.
Monotonic Stack Pattern Fixes O(n²) Stock Indexing THECODEFORGE.IO Monotonic Stack Pattern Fixes O(n²) Stock Indexing Step-by-step trace of monotonic stack reducing time complexity Input Array Stock prices or next greater element problem Initialize Empty Stack Stack stores indices of elements in decreasing order Iterate & Maintain Monotonicity Pop while top is smaller than current element Record Result on Pop Current index is next greater for popped index Push Current Index Stack remains monotonic decreasing O(n) Amortized Output Each element pushed/popped once, total linear time ⚠ Forgetting to pop all remaining elements at end After loop, remaining indices have no next greater element THECODEFORGE.IO
thecodeforge.io
Monotonic Stack Pattern Fixes O(n²) Stock Indexing
Monotonic Stack Pattern

How Monotonic Stack Works — Step by Step

Let's build a monotonic decreasing stack to find the next greater element (NGE) for each index. The stack maintains indices of elements in decreasing order of their values (biggest on top? No — actually, decreasing stack means values decrease from bottom to top). Here's the algorithm:

  1. Initialize an empty stack.
  2. For each index i from 0 to n-1:
  3. - While stack is not empty AND arr[stack.top] < arr[i]:
  4. pop top index j → record result[j] = arr[i]
  5. - Push i onto stack.
  6. Any indices still in stack have no rightward greater elements → their result stays -1.

For an increasing stack (next smaller element), flip the condition to arr[stack.top] > arr[i].

Key insight: the popped element's answer is the current element. This is a one‑pass algorithm.

Production Insight
The most common production bug: using < when you need <=.
For 'next greater or equal', change the condition.
Deduplicate by writing tests with arrays containing repeated values.
Key Takeaway
Decreasing stack → next greater. Increasing stack → next smaller.
Traverse right‑to‑left for 'previous' variants.
One condition sign change can flip all answers.
Choosing the Right Variant
IfNeed the next greater element (to the right)
UseUse monotonic decreasing stack (pop when stack top < current)
IfNeed the next smaller element (to the right)
UseUse monotonic increasing stack (pop when stack top > current)
IfNeed the previous greater element (to the left)
UseTraverse from right to left with decreasing stack
IfNeed the previous smaller element (to the left)
UseTraverse from right to left with increasing stack

Worked Example — Tracing the Algorithm

Find next greater element for [4, 5, 2, 10, 8].

i=0 (4): stack empty. Push 0. stack=[0]. i=1 (5): arr[0]=4 < 5. Pop 0. result[0]=5. Stack empty. Push 1. stack=[1]. i=2 (2): arr[1]=5 >= 2. Push 2. stack=[1,2]. i=3 (10): arr[2]=2 < 10. Pop 2. result[2]=10. arr[1]=5 < 10. Pop 1. result[1]=10. Stack empty. Push 3. stack=[3]. i=4 (8): arr[3]=10 >= 8. Push 4. stack=[3,4]. End: stack has [3,4] remaining. result[3]=-1, result[4]=-1.

Result: [5, 10, 10, -1, -1]

monotonic_stack_trace.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
def next_greater_element(arr):
    n = len(arr)
    result = [-1] * n
    stack  = []
    for i in range(n):
        while stack and arr[stack[-1]] < arr[i]:
            j = stack.pop()
            result[j] = arr[i]
        stack.append(i)
    return result

print(next_greater_element([4, 5, 2, 10, 8]))
Output
[5, 10, 10, -1, -1]
Production Insight
When debugging, print the stack after each iteration.
You'll often see stack=[index of 10, index of 8] at the end.
If you see unexpected pops, check the condition — likely using <= instead of <.
Key Takeaway
Trace by hand before coding. The single‑pass logic is subtle.
Each pop records an answer; remaining entries get -1.

Implementation — Python and Java

Below are clean implementations in Python and Java. The pattern is identical across languages: a stack of indices, a while loop with the monotonic condition, and a final sweep for unpopped indices.

Important: always store indices in the stack, not values. You need the index to fill the result array. The value is retrieved via arr[stack.top].

monotonic_stack_pattern.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def next_greater_element(arr):
    result = [-1] * len(arr)
    stack = []
    for i in range(len(arr)):
        while stack and arr[stack[-1]] < arr[i]:
            idx = stack.pop()
            result[idx] = arr[i]
        stack.append(i)
    return result

def next_smaller_element(arr):
    result = [-1] * len(arr)
    stack = []
    for i in range(len(arr)):
        while stack and arr[stack[-1]] > arr[i]:
            idx = stack.pop()
            result[idx] = arr[i]
        stack.append(i)
    return result
Production Insight
In Java, use Deque<Integer> instead of Stack (deprecated).
ArrayDeque is faster and not synchronized.
Watch out for ArrayIndexOutOfBounds when accessing arr[stack.peek()] on empty stack.
Key Takeaway
Always store indices, not values.
Use Deque in Java, list in Python.
One while loop per element structure.

Real‑World Use Cases — Beyond the Basics

The monotonic stack isn't just an interview trick. It appears in production code for:

  • Largest Rectangle in Histogram: For each bar, the area is height * (right_smaller - left_smaller - 1). Monotonic increasing stack finds both boundaries in one pass.
  • Trapping Rain Water: Maintain stack of decreasing heights; when a taller bar arrives, compute water trapped above the popped bar.
  • Stock Span Problem: For each day, find how many consecutive days before today the price was ≤ today's. Monotonic decreasing stack with indices.

Each of these uses the same core pattern with a small twist.

Histogram Trick
For largest rectangle, after the loop, process remaining stack as if a bar of height 0 appeared at index n. This avoids off‑by‑one errors.
Production Insight
When implementing histogram, don't forget to process remaining stack.
A common bug is forgetting that the right boundary is 'n' for bars never popped.
Test with a decreasing sequence (e.g., [5,4,3,2,1]) — the max area should be 5.
Key Takeaway
Monotonic stack is the backbone of histogram, rainwater, and stock span.
Each adaptation changes only the condition and what you record when popping.

Complexity Analysis — Why O(n) Amortised

Each element is pushed onto the stack exactly once. Each element can be popped at most once. Total number of push/pop operations is therefore ≤ 2n. The inner while loop may run many times for a single outer iteration, but across the entire run, the total pops equal the number of pushes. This gives an amortised O(1) per element. Space is O(n) for the stack in the worst case (e.g., decreasing array for next greater).

Formally: each iteration of the while loop pops an element, and each element is popped at most once → O(n) total while iterations.

Production Insight
Amortised analysis matters when your stack grows large (e.g., 10M elements).
Memory might spike to O(n) for sorted input – that's the worst case.
But time remains linear, which is usually the bottleneck.
Key Takeaway
Each element pushed once, popped at most once → O(n) total.
Space O(n) worst‑case. Use profiler before scaling if memory is tight.

What A Monotonic Stack Actually Is — And Isn't

A monotonic stack is just a stack that enforces a single rule: every new element must maintain the stack's sorted order before you push it. If that means popping elements that break the order, you pop. That's it. There's no magic. No hidden complexity.

Why does this matter? Because that forced ordering lets you answer one question instantly: "What was the last element that was larger (or smaller) than the current one?" That's the root of every nearest-greater/smaller-element problem. When you pop an element, you know exactly which incoming element dominated it. That relationship is the key to collapsing O(n²) brute-force scans into O(n) amortised time.

Most tutorials fluff this up with diagrams and multiple examples. Here's the raw truth: monotonic stacks are a specific tool for a narrow set of problems — finding the next/previous greater/smaller element. If you don't need that relationship, don't touch this pattern.

MonotonicStackEssence.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// io.thecodeforge — dsa tutorial

// Minimal monotonic increasing stack — finds next smaller element
import java.util.ArrayDeque;
import java.util.Deque;

public class MonotonicStackEssence {
    public static int[] nextSmallerElement(int[] prices) {
        int[] result = new int[prices.length];
        Deque<Integer> stack = new ArrayDeque<>();
        
        // Traverse right-to-left to find next smaller element
        for (int i = prices.length - 1; i >= 0; i--) {
            while (!stack.isEmpty() && stack.peek() >= prices[i]) {
                stack.pop();
            }
            result[i] = stack.isEmpty() ? -1 : stack.peek();
            stack.push(prices[i]);
        }
        return result;
    }

    public static void main(String[] args) {
        int[] prices = {8, 4, 6, 2, 3};
        int[] nextSmaller = nextSmallerElement(prices);
        for (int val : nextSmaller) {
            System.out.print(val + " ");
        }
        System.out.println();
    }
}
Output
4 2 2 -1 -1
Senior Shortcut:
If you're reversing direction (right-to-left vs left-to-right), you're solving a different but related problem. Learn one pass direction thoroughly — left-to-right for next greater — then invert for other variants. Memorising four variants is a trap.
Key Takeaway
A monotonic stack is defined by its push-time invariant: you pop until the stack is ordered, then push. Everything else is a side effect of that rule.

How To Spot A Monotonic Stack Problem Instantly

Stop memorising problem titles. Look for the pattern in the language. If the problem says "nearest element that is greater/smaller to the left/right" — that's your signal. No other technique gives you that relationship in O(n).

But here's where juniors get lost: the problem won't always say "nearest greater element". It'll say "stock span" or "trapping rain water" or "largest rectangle in histogram". Those are camouflage. The core mechanic is still: for each element, find the first element to its left or right that's larger or smaller. Learn to see through the disguise.

Three questions to ask yourself in any array problem: 1. Does the answer for each element depend on the first larger/smaller neighbour? 2. Can I process elements left-to-right or right-to-left in a single pass? 3. Does the naive O(n²) solution involve checking each element against every neighbour?

If you answered yes to at least two of those, a monotonic stack is your weapon.

StockSpanDetection.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// io.thecodeforge — dsa tutorial

// Online stock span — classic monotonic stack disguise
import java.util.ArrayDeque;
import java.util.Deque;

public class StockSpanDetection {
    static class StockSpanner {
        record Day(int price, int span) {}
        private Deque<Day> monotonicStack = new ArrayDeque<>();
        
        public int next(int price) {
            int span = 1;
            // Pop while stack top is <= current price
            while (!monotonicStack.isEmpty() && 
                   monotonicStack.peek().price() <= price) {
                span += monotonicStack.pop().span();
            }
            monotonicStack.push(new Day(price, span));
            return span;
        }
    }

    public static void main(String[] args) {
        StockSpanner spanner = new StockSpanner();
        int[] prices = {100, 80, 60, 70, 60, 75, 85};
        for (int p : prices) {
            System.out.print(spanner.next(p) + " ");
        }
        System.out.println();
    }
}
Output
1 1 1 2 1 4 6
Production Trap:
Don't confuse "monotonic stack" with "sliding window". Both use a single pass, but sliding window maintains a window size. Monotonic stack pops elements permanently — they never come back. Mix those up and you'll build a buggy hybrid that fails in edge cases.
Key Takeaway
Search for "nearest larger/smaller" relationships in the problem description. If it's there, monotonic stack is the play. If not, walk away.

Conclusion

The monotonic stack pattern fundamentally reshapes how you approach subarray and subsequence problems by trading excess comparison work for a single-pass, ordered stack. Instead of checking every element against every other element in O(n²) time, the monotonic property ensures that each element enters and leaves the stack exactly once, achieving O(n) amortised runtime. This efficiency comes from encoding dependency relationships — next greater element, nearest smaller value, or maximum width of a histogram — into stack invariants. The pattern is not magic; it is just a disciplined application of stack discipline combined with a monotonic invariant. When you see a problem asking for the next larger element, the maximum area under a histogram, or the longest valid subarray with a monotonic constraint, ask yourself: can I derive this answer from a monotonic stack? If yes, implement a while loop that pops while the invariant breaks, then push the current index. The hardest part is deciding whether the stack should increase or decrease, and that decision hinges on whether you need the next greater or next smaller element. Once you internalise that, the monotonic stack becomes one of the most reliable tools in your DSA toolkit.

MonotonicStackConclusion.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// io.thecodeforge — dsa tutorial
// Example: next greater element (monotonic decreasing stack)
import java.util.*;
class MonotonicStackConclusion {
    public int[] nextGreaterElement(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 < n; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
                int idx = stack.pop();
                result[idx] = nums[i];
            }
            stack.push(i);
        }
        return result;
    }
}
Output
For input [2,1,3], output: [3,3,-1]
Production Trap:
Do not mistake a monotonic stack for a sorted stack — elements remain in original relative order, only popped when an incoming element breaks the monotonic invariant. Double-check whether your invariant is increasing or decreasing; swapping them yields wrong results silently.
Key Takeaway
A monotonic stack reduces O(n²) comparison problems to O(n) by enforcing a single-pass invariant where each element is pushed and popped once.

What A Monotonic Stack Actually Is — And Isn't

A monotonic stack is a stack whose elements are arranged in either strictly increasing or strictly decreasing order from bottom to top. It is not a separate data structure — it is a disciplined usage pattern of a standard stack. When you push a new element, you first pop all elements that violate the monotonic order, then push. The key insight is that the stack never holds elements out of order; it enforces a sorted traversal of indices, not values. This is not a priority queue, because the order is based on value magnitude, not priority; and it is not a sorted array, because the stack only holds a subset of elements at any time. When people misuse the term, they often confuse it with a monotonic queue (used for sliding window maximum) which dequeues from both ends. The monotonic stack is strictly LIFO with a value constraint. Its power comes from the fact that when an element is popped, you know it is the first time a violating element appears to its right (or left, depending on traversal direction). That immediate contextual knowledge is what enables O(n) solutions for problems like largest rectangle in histogram or trapping rain water — it is not a catch-all for every subarray problem, only those where the answer depends on the nearest violating neighbour.

WhatMonotonicStackIs.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — dsa tutorial
// Demonstrate monotonic stack v.s. sorted stack
import java.util.*;
class WhatMonotonicStackIs {
    public static void main(String[] args) {
        int[] arr = {3, 1, 4, 2};
        Deque<Integer> monoStack = new ArrayDeque<>();
        for (int val : arr) {
            while (!monoStack.isEmpty() && monoStack.peek() > val) {
                monoStack.pop(); // maintain increasing order
            }
            monoStack.push(val);
        }
        // monoStack bottom-to-top: 1,2 (not 3,1,4,2)
        System.out.println(monoStack);
    }
}
Output
[2, 1] (bottom-to-top: [1,2]) — not sorted but monotonic increasing
Common Misconception:
A monotonic stack is NOT a data structure; it is a coding pattern. It does not maintain all elements, only those relevant to the current scanning point. Do not assume it preserves original sequence order.
Key Takeaway
A monotonic stack is a standard stack with an invariant that values are in sorted order (increasing or decreasing) — it discards elements that break the invariant, enabling O(n) nearest-neighbour lookups.
● Production incidentPOST-MORTEMseverity: high

Stock Price Indexing Slowdown

Symptom
The pipeline that computed next‑greater price for each tick (for option pricing) timed out after 30 seconds, causing backlog and missed market data windows.
Assumption
The team assumed the tick volume was small enough for O(n²) — they didn't profile before deployment. They also thought a standard for loop inside a for loop was 'simple and correct'.
Root cause
Nested loops iterate over every pair of indices — O(n²) per batch of 10,000 ticks. With 10M ticks per minute, the algorithm never finished within the 500ms per batch window.
Fix
Replaced the nested loop with a monotonic decreasing stack that computes next greater element in O(n) total time. The change was localised to a single function and required no new dependencies.
Key lesson
  • Always profile before assuming O(n²) is acceptable for variable input volume.
  • Monotonic stack is a drop‑in replacement for many 'next greater/smaller' problems — it trades memory for massive time savings.
  • Test with production data volumes in staging, not just with a handful of examples.
Production debug guideSymptom‑driven checks for the three most common mistakes3 entries
Symptom · 01
All results are -1 (no greater/smaller found)
Fix
Verify the comparison operator: for next greater you need arr[stack.top] < arr[i]; using <= treats equal values as not greater and may skip valid answers.
Symptom · 02
Answers are shifted by one index (off‑by‑one)
Fix
Check that you pop the stack before pushing the current index. A common bug: pushing first, then popping — this causes the current element to never be compared.
Symptom · 03
Wrong result for duplicates (e.g., array with repeated values)
Fix
Decide whether you need strict monotonic (< or >) or non‑strict (<= or >=). For Next Greater Element with duplicates, using <= gives the strictly greater — that's usually correct.
★ Quick Debug Cheat Sheet: Monotonic StackFive‑second checks when your monotonic stack isn't working as expected.
Output array is empty or all `-1`
Immediate action
Print the stack after each iteration to ensure elements are being pushed/popped.
Commands
`print(f'index {i}: stack = {stack}')` inside the loop
`assert len(result) == len(arr)` after the loop
Fix now
If stack stays empty, check your loop range: you may be iterating from 1 instead of 0.
Duplicate values break the logic+
Immediate action
Rerun with a small duplicated dataset and trace the condition.
Commands
`trace_condition(arr[stack.top], arr[i])`
`print(f'pop {j} because {arr[j]} {op} {arr[i]}')`
Fix now
Switch the condition sign (e.g., from < to <=) and rerun.
Monotonic Stack vs Brute Force
AspectBrute Force (Nested Loop)Monotonic Stack
Time ComplexityO(n²)O(n)
Space ComplexityO(1) (excluding output)O(n) stack overhead
ImplementationSimple, two loopsSingle loop + while, harder to get right
ScalabilityFails beyond ~10⁴ elementsHandles 10⁶+ comfortably

Key takeaways

1
A monotonic stack maintains sorted order, discarding elements that can never be useful.
2
Each element is pushed and popped at most once
total O(n) time for the entire algorithm.
3
Decreasing stack
pop when arr[new] > arr[top] → finds next greater element.
4
Increasing stack
pop when arr[new] < arr[top] → finds next smaller element.
5
Common applications
next greater element, previous smaller element, histogram rectangles, trapped rainwater.
6
Always use index stack, not value stack, to correctly fill result array.

Common mistakes to avoid

3 patterns
×

Using the wrong comparison sign (<= vs <)

Symptom
Results are off by one, or equal values are not handled correctly.
Fix
Decide if you need strictly greater/smaller or non‑strict. For 'next greater', use < for strict, <= for greater‑or‑equal.
×

Forgetting to process remaining elements in the stack at the end

Symptom
Uninitialised (or wrong) values for indices that never got popped.
Fix
After the loop, the default value (e.g., -1) already applies. But verify — if you used a different default, you must explicitly set them.
×

Storing values instead of indices in the stack

Symptom
Cannot correctly fill the result array because you don't know the index of the popped element.
Fix
Always push i (the index), not arr[i]. Retrieve value via arr[stack.peek()] when comparing.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is a monotonic stack and when should you use one?
Q02SENIOR
Walk through the 'next greater element' algorithm with a concrete exampl...
Q03SENIOR
How does a monotonic stack achieve O(n) when a naive solution is O(n^2)?
Q04JUNIOR
What is the difference between a monotonically increasing and decreasing...
Q01 of 04JUNIOR

What is a monotonic stack and when should you use one?

ANSWER
A monotonic stack maintains elements in increasing or decreasing order as they are processed. Use it for problems that ask for the 'next / previous greater / smaller element' for every index in an array. Typical examples: next greater element, largest rectangle in histogram, trapped rainwater, and stock span.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What makes a stack 'monotonic' and why does that help?
02
What is the classic 'largest rectangle in histogram' and how does the monotonic stack help?
03
Can a monotonic stack process elements from right to left?
04
What if the array is circular (e.g., next greater element II)?
N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's Stack & Queue. Mark it forged?

8 min read · try the examples if you haven't

Previous
Deque — Double Ended Queue
5 / 10 · Stack & Queue
Next
Balanced Parentheses Problem