题目描述
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
进阶:很容易想到时间复杂度为 O(n^2) 的解决方案,你可以设计一个时间复杂度为 O(n logn) 或 O(n) 的解决方案吗?
示例 1:
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
示例 2:
输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。
示例 3:
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。
解题思路
所谓「单调栈」就是栈中的元素都是依次递增或者递减的 如 [4, 3, 2, 1]
- 132模式至少存在三个数字 分别为 min, max, med
- min, max, med 顺序不可调换
- 遍历数组找 med 的位置
- 如果当前遍历大于栈顶元素 则栈的单调性被破坏,清空栈 将当前值压入栈底 将栈底元素作为med
- 如果 med max 都存在 遍历到 比med小的值 可放入min位置 返回true
/**
* 暴力求解 时间复杂度 o(n^3)
* @param nums
* @return
*/
public static boolean find132pattern_1(int[] nums) {
if (nums.length < 3){
return false;
}
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
for (int k = j + 1; k < nums.length; k++) {
if (nums[k] > nums[i] && nums[k] < nums[j]){
return true;
}
}
}
}
return false;
}
单调栈
/**
* 单调栈
* @param nums
* @return
*/
public static boolean find132pattern(int[] nums){
int len = nums.length;
if (len < 3){
return false;
}
Stack<Integer> st = new Stack<>();
int k = -1;
for (int i = len - 1;i >= 0 ;i--){
if (k > - 1 && nums[k] > nums[i]) //找到num[i]
return true;
while (!st.isEmpty() && nums[st.peek()] < nums[i])
k = st.pop(); //pop() 出去的最后一个元素就是 比 num[i] 小的所有元素中的最大元素 nums[k] 。
st.push(i);
}
return false;
}