题面:
给定一个整数序列: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].
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/132-pattern
解法一:存储区间 + 遍历
public static boolean l456(int[] nums) {
//如果数组长度小于三,返回false
if (nums.length < 3) {
return false;
}
//定义递增区间的头和尾
int head = 0;
int tail = 0;
//当前得到的数组的最小值,最大值
int min = nums[0];
int max = nums[0];
//是否是递增趋势
boolean up = false;
//定义一个储存区间的数据结构
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 1; i < nums.length; i++) {
if (nums[i] > nums[i - 1]) {
//如果是后一个比前一个大,更新尾
tail = i;
if (!up){
//更新头为第一个,确定当前是递增趋势(至少需要两个数才能判断是否为递增趋势)
head = i - 1;
//确定递增趋势,不再更新头。
up = true;
}
}
if (nums[i] < nums[i - 1]) {
//递增趋势结束
up = false;
//存放区间
map.put(head, tail);
//更新最小值和最大值
min = Math.min(nums[head], min);
max = Math.max(max, nums[tail]);
}
//判断是否应该进行与区间两端进行比较(可以提高效率)
if (nums[i] > min && nums[i] < max) {
for (Integer integer : map.keySet()) {
//判断132模式
if (nums[i] > nums[integer] && nums[i] < nums[map.get(integer)]) {
return true;
}
}
}
}
return false;
}
解法二:用栈保存‘132’中的‘3’,找到比‘2’小的数
public static boolean l456Stack(int[] nums) {
if (nums.length < 3) {
return false;
}
//132的‘2’设为Integer的最小值
int two = Integer.MIN_VALUE;
//存132的‘3’
Stack<Integer> stack = new Stack<>();
for (int i = nums.length - 1; i >= 0; i--) {
//如果‘1’ < ‘2’返回true
if (nums[i] < two) {
return true;
}
//如果当前元素比栈顶大,那么在栈中找到一个大于当前元素的,把‘2’设为上一次出栈的值
//例:栈顶依次向下为30,40,45,50,70, 80.当前元素为60,
//那么由于是倒序遍历‘50’的位置在‘60’的后面,符合‘132’的‘32’顺序,
//那么只要再找到比‘50’小的数就形成‘132’的结构‘x,60,50’
while (!stack.isEmpty() && stack.peek() < nums[i]) {
//把‘2’设为出栈的值
two = stack.pop();
}
//当前元素压栈
stack.push(nums[i]);
}
return false;
}