A clear explanation of detecting a 132 pattern using reverse traversal and a monotonic stack.
Problem Restatement
We are given an integer array nums.
We need to determine whether there exists a subsequence of three elements:
nums[i], nums[j], nums[k]such that:
i < j < kand:
nums[i] < nums[k] < nums[j]This is called a 132 pattern.
The order of indices is 1 -> 3 -> 2.
The values must look like:
small < middle < largebut they appear in the array as:
small, large, middleThe official statement defines a 132 pattern exactly as a subsequence nums[i], nums[j], nums[k] with i < j < k and nums[i] < nums[k] < nums[j].
Input and Output
| Item | Meaning |
|---|---|
| Input | An integer array nums |
| Output | True if a 132 pattern exists, otherwise False |
| Pattern | nums[i] < nums[k] < nums[j] |
| Index order | i < j < k |
Function shape:
def find132pattern(nums: list[int]) -> bool:
...Examples
Example 1:
nums = [1, 2, 3, 4]The numbers are increasing.
There is no way to choose i < j < k such that the third chosen value lies between the first and second chosen values.
Answer:
FalseExample 2:
nums = [3, 1, 4, 2]Choose:
nums[1] = 1
nums[2] = 4
nums[3] = 2The indices satisfy:
1 < 2 < 3The values satisfy:
1 < 2 < 4So the array contains a 132 pattern.
Answer:
TrueExample 3:
nums = [-1, 3, 2, 0]One valid pattern is:
nums[0] = -1
nums[1] = 3
nums[2] = 2The values satisfy:
-1 < 2 < 3Answer:
TrueFirst Thought: Brute Force
The most direct solution is to check every triplet.
class Solution:
def find132pattern(self, nums: list[int]) -> bool:
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 FalseThis is correct because it checks every possible choice of i, j, and k.
Problem With Brute Force
The brute force solution has three nested loops.
If n = len(nums), the time complexity is:
O(n^3)This is too slow for large inputs.
We need to avoid testing every triplet directly.
Key Insight
The pattern is:
nums[i] < nums[k] < nums[j]Think of the three values as:
| Pattern part | Value role |
|---|---|
nums[i] | small value, the 1 |
nums[j] | large value, the 3 |
nums[k] | middle value, the 2 |
The hard part is preserving the index order:
i < j < kA clean way is to scan from right to left.
When scanning from right to left, we can maintain information about values to the right of the current index.
The algorithm keeps:
thirdwhere third means the best candidate for nums[k], the 2 in the 132 pattern.
It also keeps a decreasing stack of possible nums[j] values, the 3 in the pattern.
If we later find a number smaller than third, then we have:
nums[i] < nums[k] < nums[j]and the index order is correct because nums[i] is to the left of both values that created third.
Algorithm
Initialize:
third = float("-inf")
stack = []Scan nums from right to left.
For each number x:
If
x < third, returnTrue.This means
xcan be the1, andthirdcan be the2.While the stack is not empty and the top of the stack is smaller than
x, pop it.Each popped value can be a valid
2, because it is smaller thanx.Update
thirdto the popped value.Push
xonto the stack as a possible future3.
If the loop finishes, return False.
Walkthrough
Use:
nums = [3, 1, 4, 2]Start:
third = -inf
stack = []Scan from right to left.
First, x = 2.
There is no smaller stack value to pop.
Push 2.
third = -inf
stack = [2]Next, x = 4.
The stack top 2 is smaller than 4, so pop it.
Now 2 becomes a candidate for the 2 in the 132 pattern:
third = 2
stack = []Push 4 as a possible 3.
third = 2
stack = [4]Next, x = 1.
Now:
x < third
1 < 2So we found:
1 < 2 < 4The pattern exists.
Return:
TrueCorrectness
The stack stores possible nums[j] values from the right side of the current scan position.
When processing a value x, every stack value smaller than x can serve as nums[k] with x serving as nums[j], because that popped value appears to the right of x and is smaller than x.
The variable third stores the largest popped value seen so far. This gives the strongest possible candidate for nums[k], because a larger nums[k] makes it easier to find a smaller nums[i].
If at some later point we find a value x such that:
x < thirdthen x appears to the left of the nums[j] and nums[k] pair that created third.
So the indices satisfy:
i < j < kand the values satisfy:
nums[i] < nums[k] < nums[j]Therefore, a valid 132 pattern exists.
If the algorithm never finds x < third, then no value to the left can complete any valid nums[j], nums[k] pair. Thus no 132 pattern exists.
Complexity
Let n = len(nums).
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Each element is pushed and popped at most once |
| Space | O(n) | The stack may store up to n elements |
Implementation
class Solution:
def find132pattern(self, nums: list[int]) -> bool:
third = float("-inf")
stack = []
for x in reversed(nums):
if x < third:
return True
while stack and stack[-1] < x:
third = stack.pop()
stack.append(x)
return FalseCode Explanation
We use:
third = float("-inf")This stores the best known candidate for nums[k], the middle value in the 132 pattern.
At the start, we have not found any candidate, so it is negative infinity.
The stack stores possible nums[j] values:
stack = []Then we scan from right to left:
for x in reversed(nums):If:
if x < third:then x can be nums[i], and third can be nums[k].
Since third was created by popping a value below some larger nums[j], we already know there is a valid nums[j] to complete the pattern.
The loop:
while stack and stack[-1] < x:
third = stack.pop()means that every smaller value to the right of x can become the 2 in the pattern, while x becomes the 3.
Finally:
stack.append(x)adds x as a possible future 3.
If no pattern is found:
return FalseTesting
def run_tests():
s = Solution()
assert s.find132pattern([1, 2, 3, 4]) is False
assert s.find132pattern([3, 1, 4, 2]) is True
assert s.find132pattern([-1, 3, 2, 0]) is True
assert s.find132pattern([1, 0, 1, -4, -3]) is False
assert s.find132pattern([3, 5, 0, 3, 4]) is True
assert s.find132pattern([1, 2]) is False
assert s.find132pattern([1, 4, 0, -1, -2, -3, -1, -2]) is True
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
[1,2,3,4] | Increasing array has no 132 pattern |
[3,1,4,2] | Standard positive case |
[-1,3,2,0] | Multiple valid patterns |
[1,0,1,-4,-3] | No valid pattern despite rises and drops |
[3,5,0,3,4] | Pattern appears after earlier noise |
[1,2] | Fewer than three elements |
[1,4,0,-1,-2,-3,-1,-2] | Negative values and late pattern |