给定一个整数序列:a1, a2, …, an,一个132模式的子序列 ai, aj, ak 被定义为:当 i < j < k 时,ai < ak < aj。设计一个算法,当给定有 n 个数字的序列时,验证这个序列中是否含有132模式的子序列。
注意:n 的值小于15000
示例1:
输入: [1, 2, 3, 4]
输出: False
解释: 序列中不存在132模式的子序列。
示例 2:
输入: [3, 1, 4, 2]
输出: True
解释: 序列中有 1 个132模式的子序列: [1, 4, 2].
示例 3:
输入: [-1, 3, 2, 0]
输出: True
解释: 序列中有 3 个132模式的的子序列: [-1, 3, 2], [-1, 3, 0] 和 [-1, 2, 0].
方法一:山脉思想+双指针
思路
借鉴山脉的思想,当找到一个上坡 A[i…k] 时,如果有 132 模式则区间 [k, n) 必定有一个下坡:下坡 [k, n) 中的数字都大于 min_element(A[i…k]) 且小于 A[k]
1996ms…算法最坏情况下会被卡成 O ( n 2 ) O(n^2) O(n2)
class Solution {
public:
bool find132pattern(vector<int>& A) {
int n=A.size();
if (n<3) return false;
int mi=A[0], i=1;
while (i<n) {
mi=min(mi, A[i]); //若mi...A[i]是上坡,则A[i]必定是最大的
if (mi != A[i]) for (int j=i+1; j<n; j++) if (A[j]<A[i] && A[j]>mi) {
return true;
}
i++;
}
return false;
}
};
复杂度分析
- Time: O ( n Q ) O(nQ) O(nQ),
- Space: O ( 1 ) O(1) O(1),
方法二:单调栈
参考别人的思路,利用最小前缀数组 mi +单调递减栈;(min[i] 表示子数组 A[0…i] 中的最小值)
- 对于一个上坡 A[i…j],在下坡 A[j+1, n) 中找一个比上坡中最小数还要大的数 tar
- tar 可以像方法一那样用 O(n) 循环找, 也可以从后往前遍历 i,维护一个单调递减栈:栈中元素都是大于 min[i] 且小于 A[i] 的,只要有这样的元素就返回 true
class Solution {
public:
bool find132pattern(vector<int>& A) {
int n=A.size();
if (n<3) return false;
int mi[n]; memset(mi, 0, sizeof mi); mi[0]=A[0];
for (int i=1; i<n; i++) mi[i]=min(mi[i-1], A[i]);
stack<int> st;
for (int i=n-1; i>0; i--) if (A[i]>mi[i]) {
while (!st.empty() && st.top()<=mi[i]) st.pop();
if (!st.empty() && st.top()<A[i]) return true;
st.push(A[i]);
}
return false;
}
};
复杂度分析
- Time: O ( n ) O(n) O(n),
- Space: O ( n ) O(n) O(n),