Introduction to Monotonic Structures
A monotonic stack or deque maintains elements in strictly increasing or decreasing order. They're perfect for "next greater/smaller element" problems.
Monotonic Increasing Stack
Elements increase from bottom to top.
def monotonic_increasing_stack(nums):
stack = []
for num in nums:
# Pop elements that violate increasing order
while stack and stack[-1] >= num:
stack.pop()
stack.append(num)
return stack
# Example
print(monotonic_increasing_stack([5, 3, 7, 1, 4]))
# [1, 4] - only increasing elements remain
Monotonic Decreasing Stack
Elements decrease from bottom to top.
def monotonic_decreasing_stack(nums):
stack = []
for num in nums:
# Pop elements that violate decreasing order
while stack and stack[-1] <= num:
stack.pop()
stack.append(num)
return stack
# Example
print(monotonic_decreasing_stack([5, 3, 7, 1, 4]))
# [7, 4] - only decreasing elements remain
Next Greater Element
Find the next greater element for each element in array.
def nextGreaterElements(nums):
"""For each element, find next greater element"""
result = [-1] * len(nums)
stack = [] # Store indices
for i in range(len(nums)):
# Pop smaller elements and set their result
while stack and nums[stack[-1]] < nums[i]:
index = stack.pop()
result[index] = nums[i]
stack.append(i)
return result
# Example
print(nextGreaterElements([2, 1, 2, 4, 3]))
# [4, 2, 4, -1, -1]
Daily Temperatures
Find how many days until a warmer temperature.
def dailyTemperatures(temperatures):
"""Days until warmer temperature"""
result = [0] * len(temperatures)
stack = [] # Monotonic decreasing (indices)
for i in range(len(temperatures)):
while stack and temperatures[stack[-1]] < temperatures[i]:
prev_index = stack.pop()
result[prev_index] = i - prev_index
stack.append(i)
return result
print(dailyTemperatures([73, 74, 75, 71, 69, 72, 76, 73]))
# [1, 1, 4, 2, 1, 1, 0, 0]
Monotonic Deque (Sliding Window Maximum)
Use deque for both ends access.
from collections import deque
def maxSlidingWindow(nums, k):
"""Maximum in each sliding window of size k"""
dq = deque() # Store indices, decreasing values
result = []
for i in range(len(nums)):
# Remove out of window
while dq and dq[0] <= i - k:
dq.popleft()
# Maintain decreasing order
while dq and nums[dq[-1]] < nums[i]:
dq.pop()
dq.append(i)
if i >= k - 1:
result.append(nums[dq[0]])
return result
print(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3))
# [3, 3, 5, 5, 6, 7]
When to Use
Use monotonic stacks/deques when you need to:
- Find next/previous greater/smaller element
- Maintain min/max in sliding window
- Track largest rectangle in histogram
- Process elements in specific order
Pattern Recognition:
- "Next greater/smaller"
- "Sliding window maximum/minimum"
- "Largest rectangle"
- "Stock span problem"
Key Takeaway
Monotonic structures help solve problems that require tracking relationships between elements efficiently. The key is maintaining order while processing and popping elements that can't be the answer.