132 Pattern — Monotonic Stack with Reverse Traversal (LeetCode 456)
Solve the 132 Pattern problem using a monotonic stack scanning right to left. Python solution tracking s3 candidates and s2 maximum, with detailed trace.
What you'll learn
- ✓What the 132 pattern is and why it is tricky
- ✓How reverse traversal with a monotonic stack finds the pattern in O(n)
- ✓The role of s2 (largest popped value) and s3 (stack candidates)
- ✓Complete Python implementation with trace
- ✓Why brute force and prefix-min approaches are insufficient
Prerequisites
- •Stack basics — see Stacks Intro
- •Monotonic stacks — see Next Greater Element
The 132 Pattern (LeetCode 456) asks whether an array contains three elements nums[i] < nums[k] < nums[j] with i < j < k. The naming comes from the relative ordering: the first is smallest (1), the third is middle (2), and the second is largest (3). Solving it in O(n) requires a clever stack trick.
The Problem
Given an array of n integers, return True if there exist indices i < j < k such that nums[i] < nums[k] < nums[j].
[3, 1, 4, 2] → True (1 < 2 < 4, at indices 1,2,3)
[1, 2, 3, 4] → False (no such triple)
[-1, 3, 2, 0] → True (-1 < 2 < 3, at indices 0,1,2)
[3, 5, 0, 3, 4] → True (0 < 3 < 5 or 0 < 4 < 5)
Why Is This Hard?
The challenge is that the three elements play different roles:
nums[i]= the “1” (smallest, leftmost)nums[j]= the “3” (largest, in the middle)nums[k]= the “2” (middle value, rightmost)
A brute-force O(n^3) check is too slow. Even an O(n^2) approach with prefix minimums is not ideal. We want O(n).
Brute Force — O(n^3)
def find132pattern_brute(nums):
"""Check all triples — O(n^3)."""
n = len(nums)
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
if nums[i] < nums[k] < nums[j]:
return True
return False
Better: Prefix Min — O(n^2)
def find132pattern_prefix(nums):
"""
Use prefix min for s1, then scan for s2 > s1.
O(n^2) time.
"""
n = len(nums)
if n < 3:
return False
min_i = [0] * n
min_i[0] = nums[0]
for i in range(1, n):
min_i[i] = min(min_i[i - 1], nums[i])
for j in range(1, n):
for k in range(j + 1, n):
if min_i[j] < nums[k] < nums[j]:
return True
return False
Optimal: Stack — O(n)
The key insight is to scan right to left and use a stack to track candidates for the “3” (the largest value, nums[j]). As we pop elements from the stack, we track the largest popped value — this becomes our candidate for “2” (nums[k], called s2).
If any element we encounter is less than s2, we have found the “1” and the pattern exists.
The Algorithm
- Initialize
s2 = -infinity(the “2” candidate, middle value) - Maintain a stack of “3” candidates (decreasing order)
- Scan from right to left:
- If
nums[i] < s2, return True (found the “1”) - Pop all stack elements smaller than
nums[i]— updates2to the largest popped value - Push
nums[i]onto the stack
- If
def find132pattern(nums):
"""
Monotonic stack scanning right to left.
Time: O(n) — each element pushed/popped at most once.
Space: O(n) — for the stack.
"""
n = len(nums)
if n < 3:
return False
stack = [] # candidates for s3 (the "3", the largest)
s2 = float('-inf') # best candidate for s2 (the "2", middle value)
for i in range(n - 1, -1, -1):
# If current element is less than s2, we found s1
if nums[i] < s2:
return True
# Pop elements smaller than current — they become s2 candidates
while stack and stack[-1] < nums[i]:
s2 = stack.pop() # largest popped = best s2
stack.append(nums[i])
return False
Detailed Trace
Example 1: [3, 1, 4, 2]
Scan right to left:
i=3, nums[i]=2:
2 < s2(-inf)? No
stack empty, push 2 stack=[2], s2=-inf
i=2, nums[i]=4:
4 < s2(-inf)? No
stack top 2 < 4 → pop, s2=2 stack=[], s2=2
push 4 stack=[4], s2=2
i=1, nums[i]=1:
1 < s2(2)? YES → return True ✓
Pattern: 1 < 2 < 4 (indices 1, 2, 3)
Example 2: [1, 2, 3, 4]
i=3, nums[i]=4: push stack=[4], s2=-inf
i=2, nums[i]=3: 3 < -inf? No.
3 < 4, no pop. push stack=[4,3], s2=-inf
i=1, nums[i]=2: 2 < -inf? No.
2 < 3, no pop. push stack=[4,3,2], s2=-inf
i=0, nums[i]=1: 1 < -inf? No.
1 < 2, no pop. push stack=[4,3,2,1], s2=-inf
return False ✓ (strictly increasing — no 132 pattern)
Example 3: [-1, 3, 2, 0]
i=3, nums[i]=0: push stack=[0], s2=-inf
i=2, nums[i]=2: pop 0, s2=0.
push 2 stack=[2], s2=0
i=1, nums[i]=3: pop 2, s2=2.
push 3 stack=[3], s2=2
i=0, nums[i]=-1:
-1 < s2(2)? YES → return True ✓
Pattern: -1 < 2 < 3 (indices 0, 1, 2)
Why Does This Work?
Let us reason about the invariants:
- Stack holds values in decreasing order (monotonic decreasing). These are candidates for the “3” — the largest element.
- s2 is the largest value ever popped from the stack. When we pop
xbecausenums[i] > x, that meansnums[i]is a better “3” andxbecomes a candidate for “2”. Sincexwas popped by something larger,s2 < some stack elementis guaranteed. - If we later find
nums[i] < s2, thennums[i]is the “1”,s2is the “2”, and the element that causeds2to be popped is the “3”.
The indices are correct because we scan right to left: the “1” is leftmost, the “3” (which pushed out s2) comes later, and “2” (s2) comes even later.
Edge Cases
- Array too short — length < 3 → always False
- All equal —
[5, 5, 5]→ False (need strict inequalities) - Strictly increasing —
[1, 2, 3, 4]→ False - Strictly decreasing —
[4, 3, 2, 1]→ False - Negative numbers — handled naturally
- Pattern at the very end —
[1, 1, 1, 3, 2]→ True
Complexity Analysis
| Approach | Time | Space |
|---|---|---|
| Brute force | O(n^3) | O(1) |
| Prefix min | O(n^2) | O(n) |
| Stack | O(n) | O(n) |
When to Use This Pattern
Use this reverse-traversal stack technique when:
- You need to find a specific ordering pattern in an array
- The pattern involves a “largest in the middle” structure
- You need to track the best second-choice (the popped values)
- Scanning from right to left gives you information about what comes after
Related Problems
| Problem | Difficulty | Key Idea |
|---|---|---|
| LeetCode 456 — 132 Pattern | Medium | This problem |
| LeetCode 503 — Next Greater Element II | Medium | Monotonic stack |
| LeetCode 334 — Increasing Triplet Subsequence | Medium | Similar triple search |
| LeetCode 42 — Trapping Rain Water | Hard | Stack with bounded regions |
Key Takeaway
The 132 Pattern is solved by scanning right to left and using a monotonic stack to track the “3” candidates. The key variable is s2 — the largest value popped from the stack — which serves as the “2” in the pattern. If any future element is less than s2, the pattern exists. This technique of tracking “the best thing that got displaced” is powerful and reusable.
Related articles
- DSA Basic Calculator I, II, III — Complete Expression Evaluation Guide
Solve Basic Calculator problems LeetCode 224, 227, and 772. Master stack-based expression evaluation with +, -, *, /, and parentheses in Python.
- DSA Largest Rectangle in Histogram Using Stack
Find the largest rectangle in a histogram using a monotonic stack in O(n). Detailed walkthrough, Python code, visual trace, and common pitfalls.
- DSA Maximal Rectangle in Binary Matrix
Find the maximal rectangle containing only 1s in a binary matrix. Builds on the largest rectangle in histogram technique with detailed explanation.
- DSA Maximum Frequency Stack — HashMap + Stack Groups (LeetCode 895)
Maximum Frequency Stack solved with HashMap and stack groups by frequency. Python implementation with step-by-step trace, complexity analysis, and design insights.