You are given an array of n
integers, nums
. Your task is to determine whether there exists a subsequence of three integers nums[i]
, nums[j]
, and nums[k]
such that:
i < j < k
(the indices are in increasing order)nums[i] < nums[k] < nums[j]
This pattern is called a 132 pattern: the first number is less than the third, which is less than the second. You must not reuse elements (each index is unique and in order). If such a pattern exists, return true
; otherwise, return false
.
Constraints:
n
is between 1 and 2 × 105nums
is an integer in the range [-109, 109]At first glance, the problem asks us to check for a specific ordering among any three elements in the array. The most straightforward way is to check all possible triplets, but this quickly becomes infeasible for large arrays due to the cubic time complexity.
We need to find three numbers with indices i < j < k
such that nums[i] < nums[k] < nums[j]
. The challenge is to efficiently search for this pattern without checking every possible combination.
The key insight is to fix one of the elements (for example, nums[j]
as the "2" in the pattern) and try to find suitable "1" and "3" elements before and after it, respectively. We also need to optimize our search by using data structures that allow us to efficiently keep track of the minimum and possible candidates for the "3" value.
As we move from brute-force to optimization, we look for ways to keep track of the minimum value to the left and efficiently search for a valid "3" to the right. Stacks and reverse traversal can help us maintain these efficiently.
Let's break down the optimized approach step-by-step:
n-1
to 0
).third
) to remember the largest "3" value we've seen so far that could form a valid pattern.third
as negative infinity (or a very small number).nums[i] < third
, we have found a valid 132 pattern and can return true
.nums[i] > stack[-1]
:
third
to be the value popped.nums[i]
onto the stack.third
is the "3". If we find a smaller "1", we've found our pattern.third
always represents a value less than the current "2", maintaining the 132 order.This approach efficiently finds the 132 pattern in linear time using a stack.
Let's use the input nums = [3, 1, 4, 2]
.
i = 3
, nums[3] = 2
third = -∞
i = 2
, nums[2] = 4
third = 2
.i = 1
, nums[1] = 1
true
.
The function returns true
as expected, since the subsequence [1, 4, 2] forms a 132 pattern.
third
variable use O(n) space in the worst case.The 132 pattern problem can be solved efficiently by observing that the "3" in the pattern can be tracked using a stack as we process the array from right to left. By maintaining the largest "3" candidate seen so far, and checking for a smaller "1" as we go, we avoid unnecessary checks and achieve linear time complexity. This approach is elegant because it leverages stack properties and reverse traversal to efficiently solve a problem that would otherwise require an impractical brute-force search.
class Solution:
def find132pattern(self, nums):
stack = []
third = float('-inf')
for num in reversed(nums):
if num < third:
return True
while stack and num > stack[-1]:
third = stack.pop()
stack.append(num)
return False
class Solution {
public:
bool find132pattern(vector<int>& nums) {
stack<int> st;
int third = INT_MIN;
for (int i = nums.size() - 1; i >= 0; --i) {
if (nums[i] < third)
return true;
while (!st.empty() && nums[i] > st.top()) {
third = st.top();
st.pop();
}
st.push(nums[i]);
}
return false;
}
};
class Solution {
public boolean find132pattern(int[] nums) {
Deque<Integer> stack = new ArrayDeque<>();
int third = Integer.MIN_VALUE;
for (int i = nums.length - 1; i >= 0; --i) {
if (nums[i] < third) return true;
while (!stack.isEmpty() && nums[i] > stack.peek()) {
third = stack.pop();
}
stack.push(nums[i]);
}
return false;
}
}
var find132pattern = function(nums) {
let stack = [];
let third = -Infinity;
for (let i = nums.length - 1; i >= 0; --i) {
if (nums[i] < third) return true;
while (stack.length && nums[i] > stack[stack.length - 1]) {
third = stack.pop();
}
stack.push(nums[i]);
}
return false;
};