题目地址:
https://www.lintcode.com/problem/636/
给定一个长 n n n的数组 A A A,问是否存在 i < j < k i<j<k i<j<k使得 A [ j ] > A [ k ] > A [ i ] A[j]>A[k]>A[i] A[j]>A[k]>A[i]。
将 A A A反序,那么问题就转化为是否存在 231 231 231的模式。思路是单调栈。我们枚举 1 1 1,那么对于每个 1 1 1,都要左边去找满足条件的 2 2 2和 3 3 3,那么可以想象,如果找到尽可能大的满足条件的 2 2 2是最好的(“满足条件”指的是对于这个 2 2 2,后面存在 3 3 3,即存在比这个 2 2 2大的数。因为找到尽可能大的 2 2 2的话,就可以在枚举 1 1 1的时候获得最大的优势)。开一个变量 l l l记录每次循环枚举的数的左边的满足条件的最大的 2 2 2。开一个单调递减的栈,对于一个新的数 x x x,如果 x x x大于栈顶,说明栈顶 t t t可以作为将来的 2 2 2使用,则更新 l l l为 max { l , t } \max\{l,t\} max{l,t}。也就是说,栈里存的是能作为最大的 2 2 2的备选数,而 l l l存的是当前循环开始的时候能作为最大的 2 2 2的数。详细来说,遍历到 A [ i ] A[i] A[i]的时候,如果一旦发现了 l > A [ i ] l>A[i] l>A[i],则说明找到了一个 231 231 231模式,返回true;否则考虑 l l l是否会被更新,如果栈顶小于 A [ i ] A[i] A[i]的话,说明栈顶 t t t可以作为 l l l,则用栈顶来更新 l l l为更大的数(如果 l l l自己更大那就不用变了),pop栈顶直到栈空或者栈顶大于等于 A [ i ] A[i] A[i],接着再把 A [ i ] A[i] A[i]进栈,因为 A [ i ] A[i] A[i]也有可能将来成为 2 2 2的一个选择。这样栈的确是单调下降的。代码如下:
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution {
/**
* @param nums: a list of n integers
* @return: true if there is a 132 pattern or false
*/
public boolean find132pattern(int[] nums) {
// write your code here
reverse(nums);
Deque<Integer> stk = new ArrayDeque<>();
int left = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
// 如果当前满足条件的2大于了nums[i],那就找到了231模式
if (left > nums[i]) {
return true;
}
// 更新可以作为2的最大数
while (!stk.isEmpty() && stk.peek() < nums[i]) {
left = Math.max(left, stk.pop());
}
stk.push(nums[i]);
}
return false;
}
private void reverse(int[] A) {
for (int i = 0, j = A.length - 1; i < j; i++, j--) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
}
时空复杂度 O ( n ) O(n) O(n)。