A stack is a linear data structure and allows LIFO (Last-In-First-Out) operations. Monotonic stacks are stacks where elements are monotonically increasing/decreasing from the bottom to the top.
Monotonic stack is a prevalent algorithm to deal with arrays when we want to find:
- The previous smaller element (PSE) — monotonic increasing stack
- The previous greater element (PGE) — monotonic decreasing stack
- The next smaller element (NSE) — monotonic increasing stack
- The next greater element (NGE) — monotonic decreasing stack
Next greater element — NGE

def nextGreaterElement(arr):
nge = [-1] * len(arr)
mono = []
for i, val in enumerate(arr):
while mono and val > arr[mono[-1]]:
nge[mono.pop()] = i # Store the index of the next greater element
mono.append(i)
return nge
# nextGreaterElement([2,3,6,1,7,5]) => [1, 2, 4, 4, -1, -1]
Next smaller element — NSE

def nextSmallerElement(arr):
nse = [-1] * len(arr)
mono = []
for i, val in enumerate(arr):
while mono and val < arr[mono[-1]]:
nse[mono.pop()] = i # Store the index of the next smaller element
mono.append(i)
return nse
# nextSmallerElement([2,3,6,1,7,5]) => [3, 3, 3, -1, 5, -1]
Previous greater element — PGE

def previousGreaterElement(arr):
pge = [-1] * len(arr)
mono = []
for i, val in enumerate(arr):
while mono and val >= arr[mono[-1]]:
mono.pop()
if mono:
pge[i] = mono[-1]
mono.append(i)
return pge
# previousGreaterElement([2,3,6,4,5,4]) => [-1, -1, -1, 2, 2, 4]
Previous smaller element — PSE

def previousSmallerElement(arr):
pse = [-1] * len(arr)
mono = []
for i, val in enumerate(arr):
while mono and val <= arr[mono[-1]]:
mono.pop()
if mono:
pse[i] = mono[-1]
mono.append(i)
return pse
# previousSmallerElement([2,3,6,4,5,4]) => [-1, 0, 1, 1, 3, 1]
Note
- The general rule is to iterate through the input array from left to right. For each
arr[i]
, compare it with the top of the monotonic stackmono
- Both NGE and PGE use monotonic decreasing stack.
NGE treats
arr[i]
as the next greater element for the top of the mono stacknge[mono.pop()]=i
, and keep popping values out untilarr[i]
is smaller, therefore it pop() and records at the same time; PGE finds the previous greater element forarr[i]
by popping all values in the stack that is smaller, until find the top element to be greater thanarr[i]
, therefore it pops() first and then recordspge[i]=mono[-1]
.
3. Both NSE and PSE use monotonic increasing stack.