携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情
根据身高重建队列
给你一个整数数组
nums
,数组中共有n
个整数。132 模式的子序列 由三个整数nums[i]
、nums[j]
和nums[k]
组成,并同时满足:i < j < k
和nums[i] < nums[k] < nums[j]
。如果nums
中存在 132 模式的子序列 ,返回true
;否则,返回false
。
分析
- 要找一个数组中有前后顺序的三个位置,对应的数字第一个小于第三个小于第二个,只要有就返回true,如果没有就返回false
暴力
- 找连续的三个数字呈现132模式,直接三重循环,可以直接得到符合132模式的三个数字和他们的位置,找到了就可以直接返回true,找不到就是false,但是三重循环时间复杂度有点高了,对这部分进行一下优化
栈
- 对三个数字分别管理,找到那个位置上最有可能出现132的三个数字
- 因为第一个数字是最小的,因此是从左向右遍历,使用一个栈N1,维护一个相对小的数,栈顶元素就是那个足够小的数字
- 接下来要寻找第三个数字,第三个数字大于第一个数字小于第二个数字,但是位置在第一个数字和第二个数字的后面,因此从右往左遍历能更快的找到第三个数字,在从右往左寻找第三个数的遍历中,当数字大于N1中的对应位置的数字,那这个数字可能是第二个数字,使用栈N2,同样的策略,N2的栈顶元素也是能提供132模式的最优解的值,当第二个数字的栈顶元素小于对应位置的N1中的值,就出栈,当N2的栈顶元素大于N1对应位置的数字,小于在当前遍历过程中第三个数字的值,就返回true,当从右到左遍历完成后,没有符合条件的就是false
代码
var find132pattern = function(nums) {
if (nums.length < 3) return false;
let N2 = []; // potential candidates, number 2
let N1 = [nums[0]]; // the smallest number, number 3
for (let i=1;i<nums.length;i++) {
N1.push(Math.min(N1[N1.length-1], nums[i]));
}
for (let i=nums.length-1;i>=0;i--) { // number 3
if (nums[i] > N1[i]) {
while (N2.length!=0 && N2[N2.length-1] <= N1[i]) N2.pop();
if (N2.length!=0 && N2[N2.length-1] < nums[i]) return true;
N2.push(nums[i]);
}
}
return false;
}
总结
- 三重循环,分别遍历三个位置上的数字是简单的解法,时间复杂度是O(n^3),对复杂度进行降幂,就需要尽可能的在一次遍历中得到尽可能多的中间数或者最终答案。这个题目就通过栈这种特殊的数据结构,通过栈顶元素解读为最有可能出现132模式数字的设定,O(n)就可以得到结果
- 今天也是有收获的一天