Leetcode-456 132 模式

久违的题解,大概近一周的时间没有写了。

题目说明

给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
进阶:很容易想到时间复杂度为 O(n^2) 的解决方案,你可以设计一个时间复杂度为 O(n logn)O(n) 的解决方案吗?
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。

输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。

解答

我承认这题我不会,只能去看题解了,像我这种菜鸡,题解也看了很久才看懂。想讲出来真的很难。
这题采用的是单调栈的解法,与一般的单调栈问题不同,栈里的元素不再是问题的解,而是通过栈顶元素进行求解。
问题要求判断是否存在 1 - 3 - 2 类型的子数组。
想了很长时间,其实问题的关键在于,我们想让“2”尽可能的大,这样在遍历的过程中对“1”的要求就变小了。因此从后向前遍历数组,这样可以对“2”的情况进行遍历,寻找符合条件的“2”。同时我们用一个变量maxn来记录“2”的可能的最大值。
在遍历时,用栈来对数据进行记录,假如栈中的数据均比maxn大,并且栈顶元素比maxn晚出现同时遍历到的数据比maxn小,那么就出现1-3-2模式。
我们需要记住一点,那就是“3”是有可能变成“2”的,前提条件是在它之前有比它大的数。因此,我们的思路是用栈来记录遍历的数据,前提条件是它要比maxn大。我们在从后向前遍历的时候,有可能在后面有一个比较大的数可以作为“2”,只要在前面有一个比它大的数。那么此时这个数其实就没有必要存储了,因为无用了,我们已经判断过了。就比如,假如一个子序列是[4,2,1,3]。那么“3”就是4,“2”就是3,无需考虑“2”是1或2的情况。
所以栈存储的数据其实是有可能成为“2”但是到目前为止它前面的数还没有比它大的,如果有比它大的,那么数据就可以出栈了。这样其实很清楚了,栈是单调栈,也就是从栈底到栈顶,数据依次减小。每当遍历到一个数据时,在它之后的比它小的数我们就不需要了,只需要知道比它小的最大的数是多少,方便我们找出“1”。所以,每当遍历到一个数,如果它比maxn小,那么就出现1-3-2模式,因为栈顶元素一定比maxn大;将栈中比它小的数出栈;同时更新maxn。
如果到最后还没有这种情况,那么就不存在1-3-2的子序列。
具体代码如下所示:

class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        int len = nums.size();
        stack<int> st;
        int maxn = INT_MIN;
        st.push(nums[len - 1]);
        for(int i = len - 2; i >= 0; i--){
            if(nums[i] < maxn){
                return true;
            }
            while(!st.empty() && nums[i] > st.top()){
                maxn = st.top();
                st.pop();
            }
            if(nums[i] > maxn){
                st.push(nums[i]);
            }
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值