LeetCode刷题(栈) --456. 132模式

题目

给定一个整数序列: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

解释: 序列中有 1132模式的子序列: [1, 4, 2].
示例 3:

输入: [-1, 3, 2, 0]

输出: True

解释: 序列中有 3132模式的的子序列: [-1, 3, 2], [-1, 3, 0][-1, 2, 0].

思路

按照题目要求,要寻找132数列,即中间的数最大(分别定为num_1,num_3,num_2),因此我们可以将序列分成两部分。以num_3为中线,在num_3的前部分找到最小的序列(num_1的集合,为什么是集合?因为对于每一个不同位置的序列,该位置之前的最小数都不一定是相同的,因此我们只能找到每一个序列上对应的当前最小值),在后半部分找到比num_3小的并且比num_1序列上当前位置值大的数,如果存在,即返回真。

  1. 新定义一个vector容器min_num集合(长度为输入序列的长度,一一对应),给该集合赋值,该值为从左开始,到当前index最小的值。这就代表着在当前数之前的最小数,即num_1;
  2. 定义一个栈,存放栈顶最小,栈底最大的一个降序序列。该序列代表着num_2的可能取值,只找到符合情况的最小值。
  3. 给栈赋值操作:从输入序列的左边开始执行循环递减。循环中的判断变量即为num_3,而栈顶则为num_2。
  • 首先判断当前的值大于min_num中对应的值
  • 如果当前栈顶的值小于当前min_num对饮值,则表明不符合条件,pop
  • 执行上一步,直到栈顶值大于min_num
  • 判断栈顶是否小于当前值,是,则返回true,找到132序列
class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        //1.
        int n = nums.size();
        vector<int> mi_1;
        int min_num=nums[0];
        for(int i=0;i<n;++i)
        {
            if(nums[i]<min_num) min_num = nums[i];
            mi_1.push_back(min_num);
        }
        //2.
        stack<int> st;
        //3.
        for(int i=n-1;i>=0;--i)
        {
            if(nums[i]>mi_1[i])
            {
                while(!st.empty()&&st.top()<=mi_1[i]) st.pop();
                if(!st.empty()&&st.top()<nums[i]) return true;
                st.push(nums[i]);
            }
        }
        return false;
    }
};

总结

借用一下大佬的总结:

解释一下为啥用递减栈:

我们需要找a[k] < a[j] 且 a[k] > min[j] ,假如不用栈,对于每一个j,我们需要遍历j之后的所有元素来判断是否符合条件,on^2复杂度,

因为有min[j-1] <= min[j], 利用递减栈,栈中大于等于min[j] 的元素都出栈了,那么当找下一轮j-1时,上一轮出栈的元素一定也是不符合条件提前出局。这样就可以利用上一轮的结果避免重复判断,将复杂度缩小到On。

为什么从后往前遍历?因为找k的时候k在j后面,所以得是从后往前遍历,这样栈中元素都是j后面的元素。

为什么是递减栈? 如果是递增栈,那么对于a[k] > min[j], 如果栈顶满足条件,我们还需要检查a[k] < a[j].如果不符合条件,我们需要弹出该元素继续寻找下一个元素。这个被弹出的元素a[k]。因为a[k] > min[j] >= min[j-1]。却因为被弹出栈导致下一轮j-1无法搜索。因此无法用递增栈。

为什么我们找a[k] < a[j] 且 a[k] > min[j] 的时候,是先找大于min[j]的元素,然后再比较该元素与a[j]的关系。而不是反过来,先找小于a[j]的元素,再比较该元素与min[j]的关系? 相信你应该有了答案。

总结:利用单调栈以及上一轮与下一轮的联系(min[j-1] <= min[j])避免了同一元素的重复判断,从而降低时间复杂度。

你可能感兴趣的:(算法,算法,python,数据结构,leetcode)