132 Pattern — Monotonic Stack Right-to-Left in O(n)
Advertisement
Problem Statement
Given an array of n integers nums, a 132 pattern is a subsequence of three integers nums[i], nums[j], nums[k] such that i < j < k and nums[i] < nums[k] < nums[j]. Return true if there is a 132 pattern in nums, otherwise return false.
Constraints:
n == nums.length1 <= n <= 2 * 10^5-10^9 <= nums[i] <= 10^9
Input: nums = [1,2,3,4]
Output: false
Explanation: No 132 pattern exists in a strictly increasing array.Input: nums = [3,1,4,2]
Output: true
Explanation: i=1 (1), j=2 (4), k=3 (2). 1 < 2 < 4. ✓Input: nums = [-1,3,2,0]
Output: true
Explanation: -1 < 0 < 3 (or 2).Why This Problem Matters
LeetCode 456 132 Pattern is a Bloomberg favorite that also shows up regularly at Amazon and Google. It is one of the few problems where a monotonic stack scanned right-to-left is the optimal solution. Most candidates struggle because the natural reading order is left-to-right, so the trick of reversing direction is genuinely tricky.
This problem teaches:
- How to identify a "next" relationship — here, the next number to the right that is smaller than the current peak.
- Why scanning direction matters when applying a monotonic stack.
- A subtle pattern: keep track of the best candidate for
nums[k](the "2" in 132) while ensuring it remains less thannums[j](the "3").
It is the canonical bridge between "next greater element" problems and harder problems like LC 1856 and LC 2104.
The Core Insight
A 132 pattern needs:
nums[i]= some small value (the "1").nums[j]= a peak value (the "3").nums[k]= a middle value strictly betweennums[i]andnums[j], andk > j.
We scan from right to left and maintain:
- A monotonically decreasing stack from bottom to top (top has the smallest value seen so far) of candidate
nums[j]values. - A variable
thirdrepresenting the best (largest) value we have already discarded from the stack — this is our candidatenums[k](the "2").
When we examine nums[i]:
- If
nums[i] < third, we have found a pattern:nums[i] = "1", the popped element that becamethird = "3"(wait — actually: the element that promotedthirdwas aj > iandthirdis a number to its right, smaller than it). Returntrue. - Otherwise, while the stack top is less than
nums[i], pop and updatethird = max(third, popped). This means:nums[i]is bigger than something on the stack, so we promote that smaller value to be anums[k]candidate, withnums[i]itself becoming the newnums[j]. - Push
nums[i].
The clever part: third is always strictly less than at least one value to its left in the stack (the value that pushed it out). So if we ever find an nums[i] < third, the triplet (nums[i], that_value, third) forms a valid 132 pattern.
O(n) time because each element is pushed and popped at most once.
Visual Dry Run
Input: nums = [3, 1, 4, 2]. Scan right to left: indices 3, 2, 1, 0.
| i | nums[i] | Stack (top right) | third | Action |
|---|---|---|---|---|
| 3 | 2 | [2] | -inf | push |
| 2 | 4 | [4] | 2 | pop 2, third=2, push 4 |
| 1 | 1 | [4] | 2 | 1 < third (2)? Yes -> return true |
Found pattern at indices (1, 2, 3) with values (1, 4, 2): 1 < 2 < 4. ✓
Input: nums = [1, 2, 3, 4].
| i | nums[i] | Stack | third | Action |
|---|---|---|---|---|
| 3 | 4 | [4] | -inf | push |
| 2 | 3 | [4,3] | -inf | 3 < 4, push (decreasing maintained) |
| 1 | 2 | [4,3,2] | -inf | 2 < 3, push |
| 0 | 1 | [4,3,2,1] | -inf | 1 < 2, push; 1 < third? No |
Loop ends. Return false. No 132 pattern in a strictly increasing array.
Solution (Optimal)
# Python — monotonic stack right-to-left, O(n) time, O(n) space
def find132pattern(nums: list[int]) -> bool:
stack = []
third = float('-inf')
for i in range(len(nums) - 1, -1, -1):
if nums[i] < third:
return True
while stack and stack[-1] < nums[i]:
third = max(third, stack.pop())
stack.append(nums[i])
return False// JavaScript — monotonic stack right-to-left, O(n) time, O(n) space
function find132pattern(nums) {
const stack = [];
let third = -Infinity;
for (let i = nums.length - 1; i >= 0; i--) {
if (nums[i] < third) return true;
while (stack.length && stack[stack.length - 1] < nums[i]) {
third = Math.max(third, stack.pop());
}
stack.push(nums[i]);
}
return false;
}# Brute force for reference, O(n^2) time
def find132patternBrute(nums: list[int]) -> bool:
n = len(nums)
for j in range(n):
min_left = min(nums[:j], default=float('inf'))
for k in range(j + 1, n):
if min_left < nums[k] < nums[j]:
return True
return FalseComplexity:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Brute force | O(n^2) | O(1) | TLE for n = 2*10^5 |
| Monotonic stack right-to-left | O(n) | O(n) | Optimal |
Common Mistakes
-
Scanning left-to-right. The pattern
nums[i] < nums[k] < nums[j]withi < j < kis hard to detect left-to-right because you do not know which value will be the future "2." Scanning right-to-left lets us treat each element as a potentialnums[i]while keepingnums[k]andnums[j]candidates already known. -
Not updating
thirdcorrectly.thirdmust be the maximum popped value, not the most recent. Some popped value might be a better (larger) candidate fornums[k]. -
Pushing before checking. If you push
nums[i]first and then checknums[i] < third, you can falsely matchnums[i]against itself. -
Treating "<" as "<=" in the comparison. The pattern requires strict inequalities. Using
<=gives false positives for arrays like[1, 2, 2]. -
Stack monotonicity confusion. The stack stays monotonically decreasing from bottom to top while scanning right-to-left because we only pop when a strictly larger element arrives.
Interview Tips
- Open with: "I will scan right-to-left because the relationship
nums[i] < nums[k] < nums[j]withi < j < kis more naturally tracked by maintaining futurejandkcandidates as we move backward throughi." - Justify the monotonic stack: "A decreasing stack lets me know that when an element pops, the popper is a larger value to its left — perfect candidate for
nums[j]." - Walk through the example
[3, 1, 4, 2]to convince the interviewer the logic is sound. The right-to-left scan is unintuitive enough that most interviewers want to see a trace. - If the interviewer asks "what about
[1, 4, 2, 3]?" walk through it: scan findsthird = 2after popping, then sees1 < 2, returnstrue.
Follow-up Questions
- Return all 132 patterns. Tracking just
thirdis no longer enough; you must reconstruct triples — typicallyO(n^2)for output sensitivity. - Find the longest 1...3...2 subsequence. Generalizes to LIS-style DP and is much harder.
- Streaming variant. Incrementally maintain the answer as
numsgrows — non-trivial extension. - 123 pattern. Strictly increasing — trivial in
O(n)with two pointers. - Generalized k-pattern detection. Brute force is
O(n^k); segment trees or BIT can reduce some cases.
Key Takeaways
- 132 Pattern is the canonical "scan right-to-left with a monotonic stack" problem on the LeetCode catalog.
- Maintain a decreasing stack of candidate
nums[j]values; when you pop, the popped value becomes a candidate fornums[k]("2"), tracked inthird. - A 132 pattern is found when the current element is strictly less than
third— that means a smallernums[i], a poppednums[k], and the poppernums[j]form a valid triple. O(n)time andO(n)space because each element is pushed and popped at most once.- The right-to-left direction is the key insight — many monotonic stack problems benefit from reversing the scan direction.
- Watch out for
<=vs<and for resettingthirdonly viamax(third, popped).
Advertisement