一、题目
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
点击查看原题
难度级别: 中等
二、思路
1)TreeMap
使用暴力法,将会先确定j
位置,找到j
位置元素之前的最小值nums[i]
,然后在j
位置后面找到位置k
,让nums[i] < nums[k] < nums[j]
,如果能够找到k
,则返回true
,没有找到k
就将j
后移一位
这里将暴力法中查找k
的方式,使用TreeMap
加速查找
2)单调栈
题目要求找到132
模式,让i<j<k
,且nums[i] < nums[k] < nums[j]
,先找到k
和j
,使用递减栈从后面开始遍历,将递减栈出栈的最大元素为nums[k]
,如果遍历到元素小于nums[k]
,那么就找到了132
模式的序列,下面解释一下为什么这么做:
1、递减栈能够确保栈中元素是递减排列,当新遍历的元素大于栈顶元素,则出栈
2、k
指向的元素为出栈的最大元素,则可以确定,nums[k]
一定是一个尽可能接近nums[j]
的数
3、由于nums[k]
和nums[j]
形成了nums[k]<nums[j]
,接下来只需要遍历到元素小于nums[k]
的情况,就找到了序列
三、代码
1)TreeMap
class Solution {
public boolean find132pattern(int[] nums) {
TreeMap<Integer, Integer> tm = new TreeMap();
int leftMin = nums[0];
for (int i = 1; i < nums.length; i++) {
tm.put(nums[i], tm.getOrDefault(nums[i], 0) + 1);
}
for (int i = 1; i < nums.length - 1; i++) {
if (tm.get(nums[i]) == 1) {
tm.remove(nums[i]);
} else {
tm.put(nums[i], tm.get(nums[i]) - 1);
}
if (leftMin > nums[i]) {
leftMin = nums[i];
continue;
}
Integer t = tm.lowerKey(nums[i]);
if (t != null && t > leftMin) {
return true;
}
}
return false;
}
}
2)单调栈
class Solution {
public boolean find132pattern(int[] nums) {
List<Integer> desc = new ArrayList();
int k = Integer.MIN_VALUE;
for (int j = nums.length - 1; j >= 0; j--) {
if (k > nums[j]) {
return true;
}
while (desc.size() != 0 && desc.get(desc.size() - 1) < nums[j]) {
k = Math.max(k, desc.get(desc.size() - 1));
desc.remove(desc.size() - 1);
}
desc.add(nums[j]);
}
return false;
}
}
时间复杂度为O(n)
,空间复杂度为O(n)