A monotonic stack finds nearest greater or smaller neighbors in linear time by keeping unresolved array indices in sorted order. The same boundary idea also finds the largest rectangle in a histogram: when a shorter bar arrives, it closes the widest possible span for taller bars still on the stack.
What a monotonic stack does
A monotonic stack is a stack whose candidate values stay ordered as elements are processed. In common array problems, it holds indices rather than values: an index gives access to its value and position, which makes it possible to return a neighbor, a distance, or a range width.
As an Amazon Associate I earn from qualifying purchases.
The key is that candidates remain on the stack only while their answer is unresolved. When a new element breaks the stack’s ordering, it can settle the answer for one or more candidates. This is useful for questions about the nearest greater or smaller element on one side, or about a span bounded by the first smaller or larger element. It is not a general-purpose shortcut for every array scan.
For next-greater-to-the-right, scan left to right and keep unresolved indices in decreasing value order, with the largest unresolved candidate at the bottom and the smallest at the top. When the current value is greater than the top candidate’s value, it is that candidate’s first greater value to the right. Pop the candidate and record the answer; keep popping while the current value resolves more candidates.
#1 Best Overall
Find the next greater element to the right
Initialize each answer to the problem’s no-answer marker, such as -1. Push each index after resolving any smaller values above it:
answer = [-1] * n
stack = [] # indices whose next greater value is unresolved
for i in range(n):
while stack and values[stack[-1]] < values[i]:
j = stack.pop()
answer[j] = values[i]
stack.append(i)
The comparison defines what counts as a match. With <, equal values do not resolve one another: the answer must be strictly greater. If equal values are meant to qualify, use <= instead. Decide this from the problem statement rather than assuming one rule fits every variant.
Rank #2
- color: White
- INTRODUCTION TO ALGORITHMS, FOURTH EDITION
Any indices still on the stack after the scan have no qualifying greater value to their right, so their answers remain at the no-answer marker. The pattern and its linear-time reasoning are described in CrackAlgo’s monotonic-stack tutorial.
Why the nested loop is still linear
The while loop does not make the total work quadratic. Each index is pushed once and popped at most once. Across the entire scan, those stack operations total O(n), so the algorithm runs in O(n) time and uses O(n) additional space in the worst case. The unresolved stack can contain every index, for example when values never increase enough to resolve earlier candidates.
Rank #3
Return a position or a distance instead of a value
The resolution rule stays the same when a problem asks for a different output. For a popped index j, the current index i is the next greater position. A Daily Temperatures-style answer records i - j, the number of positions to wait, rather than values[i].
Adapt the scan for common variants
Circular next greater element
In a circular array, an element near the end may have its next greater value near the beginning. Scan a logical doubled array so the second traversal can resolve candidates left over from the first. Push original indices only during the first traversal; this lets the second pass provide look-ahead without adding duplicate candidates. See the NeetCode monotonic-stack templates for this scan pattern.
Choose a problem by the relationship it asks for
- Next Greater Element I: resolve each value’s next greater value and use the resulting mapping where the problem requires it.
- Next Greater Element II: use the circular scan to allow a greater value to wrap from the beginning.
- Daily Temperatures: resolve the next warmer position and return the distance between positions.
- Largest Rectangle in Histogram: find how far each bar can extend before a shorter bar limits its rectangle.
- Maximal Rectangle: build consecutive-one heights for each matrix row, then run the histogram algorithm on those heights.
Use shorter neighbors to find the largest histogram rectangle
For a bar of height h, imagine making it the limiting height of a rectangle. The rectangle can extend across adjacent bars until it meets a strictly shorter bar on either side. Those nearest shorter bars set the boundaries; the candidate area is h × width.
With an increasing stack of indices, a shorter current bar closes the span of each taller bar it pops. For a popped index j, the current position is the right boundary. After popping, the new stack top is the nearest shorter bar on the left; if the stack is empty, use left = -1. The width and area are:
Best Value
- Binding: paperback
- Language: english
- It ensures you get the best usage for a longer period
width = right - left - 1
area = heights[j] * width
This boundary interpretation is laid out in Masst Docs’ monotonic-stack and deque guide.
Single-pass implementation with a trailing sentinel
A virtual trailing zero causes all remaining positive-height bars to be popped at the end. It is a convenient way to ensure every candidate gets measured; treat the sentinel as a scan aid, not as an actual histogram bar.
best = 0
stack = [] # indices of increasing heights
for right in range(len(heights) + 1):
current = heights[right] if right < len(heights) else 0
while stack and heights[stack[-1]] > current:
j = stack.pop()
left = stack[-1] if stack else -1
width = right - left - 1
best = max(best, heights[j] * width)
if right < len(heights):
stack.append(right)
This version pops only when the current height is strictly smaller. Equal-height indices remain on the stack; when a later shorter bar arrives, each is popped and its width is computed against the remaining left boundary. Another valid convention is to pop on less-than-or-equal and collapse equal candidates. Either convention can work, but the comparison and width logic must agree. The shown sentinel assumes nonnegative histogram heights.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Trace the decisive pops
For [2, 1, 5, 6, 2, 3], the height-2 bar at index 4 closes the candidates at heights 6 and 5. The height-6 bar has width 1 and area 6. After it is popped, the height-5 bar’s left boundary is the height-1 bar at index 1, so its width is 2 and its area is 10. That is the largest rectangle: height 5 across the adjacent bars of heights 5 and 6.
Recognize the pattern and avoid common mistakes
- Ask whether the answer is a nearest qualifying neighbor or boundary. If a candidate can be permanently resolved when a later value breaks the ordering, a monotonic stack may fit.
- State the invariant. Specify whether stack values increase or decrease and whether equal values stay or pop.
- Keep indices when position matters. Indices support both value lookup and computations such as waiting distance or histogram width.
- Check what happens to unresolved indices. Next-greater answers need the problem’s no-answer marker; histogram candidates need a final flush, often with a sentinel.
- Test duplicates and edges. Equal values, a strictly increasing sequence, a strictly decreasing sequence, and an empty or one-bar histogram expose many comparison and boundary mistakes.
Once the invariant and output are clear, the same idea transfers cleanly: a popped index has just found its first qualifying neighbor, or—when working on a histogram—just reached the boundary that limits its span.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




