一起刷LeetCode——132 模式(栈)

36 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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)就可以得到结果
  • 今天也是有收获的一天