力扣解题思路:456. 132模式 纠错记录

456. 132模式

思路:在这里插入图片描述
扫了一眼题目,感觉需要用到栈,我的想法是用用栈来保存递增序列(栈顶最大),遍历一遍数组,当当前元素比栈顶元素大或等于就入栈,比栈顶小就满足条件啦~

    public boolean find132pattern(int[] nums) {
            Stack<Integer> stack = new Stack<>();
            for(int i=0;i<nums.length;i++){
                if(stack.isEmpty() || stack.peek()<=nums[i]){
                    stack.add(nums[i]);
                    continue;
                }
                if(!stack.isEmpty() && stack.size()>1 && nums[i]<stack.peek()){
                    return true;
                }
            }
        return false;
    }

但是这样我发现有漏洞由于我们值存大于栈顶的元素,那么【1,-3,0,-2】这种情况我们就得不出【-3,0,-2】这个子序列,因为-3被限制无法入栈,所以我们再外层加一个循环,这样每个元素都有入栈的机会啦~

class Solution {//错误,我以为满足nums[i]<nums[j]>nums[k]就行了,但是题目要求是nums[i]<nums[k]<nums[j]
    public boolean find132pattern(int[] nums) {
        for(int j=0;j<nums.length;j++){
            Stack<Integer> stack = new Stack<>();
            for(int i=j;i<nums.length;i++){
                if(stack.isEmpty() || stack.peek()<=nums[i]){
                    stack.add(nums[i]);
                    continue;
                }
                if(!stack.isEmpty() && stack.size()>1 && nums[i]<stack.peek()){
                    return true;
                }
            }
        }
        return false;
    }
}

但是这样还是错了!!题目要求是nums[i]<nums[k]<nums[j],而我只满足了nums[i]<nums[j]>nums[k] /(ㄒoㄒ)/~~

不过改改就行啦,只要我们加一个限制条件使nums[i]<nums[k](即nums[i]>nums[j])满足就可以了:

class Solution {//对,但是超时
    public boolean find132pattern(int[] nums) {
        for(int j=0;j<nums.length;j++){
            Stack<Integer> stack = new Stack<>();
            for(int i=j;i<nums.length;i++){
                if(stack.isEmpty() || stack.peek()<=nums[i]){
                    stack.add(nums[i]);
                    continue;
                }
                if(!stack.isEmpty() && stack.size()>1 && nums[i]<stack.peek() && nums[i]>nums[j]){
                    return true;
                }
            }
        }
        return false;
    }
}

这样的确没问题,但是超时了。。。

于是!!我想到之前用回溯做排列组合的时候是去重了的,这里也需要去重呀,比如外层循环中相邻两个数相同那么只需遍历一次即可,加上这个判断if(j>0 && nums[j] == nums[j-1]) continue;就可以啦:

class Solution {//通过
    public boolean find132pattern(int[] nums) {
        if(nums.length < 3) return false;
        for(int j=0;j<nums.length;j++){
            if(j>0 && nums[j] == nums[j-1]) continue;
            Stack<Integer> stack = new Stack<>();
            for(int i=j;i<nums.length;i++){
                if(stack.isEmpty() || stack.peek()<=nums[i]){
                    stack.add(nums[i]);
                    continue;
                }
                if(!stack.isEmpty() && stack.size()>1 && nums[i]<stack.peek() && nums[i]>nums[j]){
                    return true;
                }
            }
        }
        return false;
    }
}

终于通过了!!但是时间复杂度仍然太高,我们如何才能去掉一层循环呢?我确实没想出来,于是就参考了下别人的答案。

别人的思路是这样的,首先是倒着遍历,因为如果我们固定最后两个数找第一个数会比较方便,因为第一个数只需满足比第三个数小即可。

好,接下来我们还是需要用到栈,栈中保存一个递减序列(栈顶最小),也就是只要小于等于栈顶的元素都是直接入栈,如果遇到比栈顶大的元素,那就意味着我们找到了第二个数,也就是最大的那个数,那呢第三个数一定在栈中!(因为第三个数索引比第二个数大,我们是倒着遍历的)那么我们选栈中哪个数作为第三个数呢?我们用栈底的数,因为栈底的数最大,选一个大的数能给第一个数留下更多的选择空间,那么我们将这个第三个数记录为last(栈要清空),每再遍历一个数小于last就可以返回true啦:

class Solution {
    public boolean find132pattern(int[] nums) {
        int n = nums.length;
        int last = Integer.MIN_VALUE; // 132中的2
        Stack<Integer> sta = new Stack<>();// 用来存储132中的3
        if(nums.length < 3) return false;
        for(int i=n-1; i>=0; i--){
            if(nums[i] < last) // 若出现132中的1则返回正确值,此时能保证132中的1:num[i]在最前面(因为是从后往前遍历)
                return true;
            // 若当前值大于或等于2则更新2(2为栈中小于当前值的最大元素)
            while(!sta.isEmpty() && sta.peek() < nums[i]){//若栈中的元素一直小于num[i]则栈会被清空并最后加入最大的那个元素
                last = sta.pop();//pop出来的都是之前遍历过的数,所以能保证132中2在3的后面出现(因为数组从后面开始遍历的)(这是pop出来的是比nums[i]小的一个最大的数,因为last最终等于栈底)
            }
            // 将当前值压入栈中
            sta.push(nums[i]);
        }
        return false;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值