Monotonic Stack
Use when: Next greater/smaller element, span problems, largest rectangle.
Complexity: O(N) - each element pushed and popped at most once
Next Greater Element
def next_greater(nums):
n = len(nums)
result = [-1] * n
stack = [] # stores indices, decreasing values
for i in range(n):
while stack and nums[i] > nums[stack[-1]]:
idx = stack.pop()
result[idx] = nums[i]
stack.append(i)
return resultNext Smaller Element
def next_smaller(nums):
n = len(nums)
result = [-1] * n
stack = [] # stores indices, increasing values
for i in range(n):
while stack and nums[i] < nums[stack[-1]]:
idx = stack.pop()
result[idx] = nums[i]
stack.append(i)
return resultPrevious Greater Element
def prev_greater(nums):
n = len(nums)
result = [-1] * n
stack = []
for i in range(n):
while stack and nums[stack[-1]] <= nums[i]:
stack.pop()
if stack:
result[i] = nums[stack[-1]]
stack.append(i)
return resultLargest Rectangle in Histogram
def largest_rectangle(heights):
stack = [] # monotonic increasing stack of indices
max_area = 0
heights.append(0) # sentinel
for i, h in enumerate(heights):
while stack and heights[stack[-1]] > h:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
stack.append(i)
return max_areaSignals in a Problem
- “Next greater/smaller element”
- “Daily temperatures”, “stock span”
- “Largest rectangle” / “trap rain water”
- Need to find nearest element satisfying a condition