【剑指Offer】个人学习笔记_31_栈的压入、弹出序列

本文介绍了如何使用Java解决LeetCode题目31,利用栈的压入和弹出操作判断序列是否合法,通过对比和优化不同解法,重点讲解了不使用辅助栈的高效解决方案。

刷题日期:21:3224 星期三 2021年4月7日

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

剑指 Offer 31. 栈的压入、弹出序列

难度中等161

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

  1. 0 <= pushed.length == popped.length <= 1000
  2. 0 <= pushed[i], popped[i] < 1000
  3. pushedpopped 的排列。
题目分析

并不是简单的倒序,首先判断是否完全是倒序,如果不是的话从第一个输出开始是否与原栈匹配,后面是否为倒序,如果有误则错误。

如果下一个是栈顶,直接弹出

如果不是,则把剩下的压入辅助栈,直到栈顶是,都压入还不满足,则错误。

初始解答:

对Java栈的操作还比较生,参考了【剑指Offer】个人学习笔记_09_ 用两个栈实现队列的操作方法。

class Solution {
    Stack<Integer> stack1; //两个辅助栈
    Stack<Integer> stack2;
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        boolean bP = false; //判断flag
        stack1 = new Stack<>(); //栈的定义方法,学习了
        stack2 = new Stack<>(); //感觉其实是链表
        stack1.add(pushed[0]); //初始化
        int i = 0;
        for (int j = 0; j < popped.length; j++) {
            while(stack1.pop() != popped[0]) { //如果不是则一直压
                stack1.add(pushed[i++]);
                if (i > pushed.length) return false;
            }
            //如果上面跑完而且没返回错误则说明找到了项
        }
        //一直找popped元素
        

        return true;
    }
}

写不出来,还是参考别人的吧。

参考了方法一:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Deque<Integer> stack =new ArrayDeque(); //定义辅助栈
        int j = 0;
        for (int elem:pushed) { //pushed里面的每一个元素遍历
            stack.push(elem); //挨个压入
            while (j < popped.length && !stack.isEmpty() && stack.peek() == popped[j]) {
                // 当所判断的元素还属于popped,辅助栈非空,并且栈顶元素为popped目前第一个元素
                stack.pop();
                j++;
            }
            //循环一次代表找到一个
        }
        return j == popped.length; //相等则意味着全找到了
    }
}

用了辅助栈,j自增和两层循环,效率较低

执行结果:通过

显示详情

执行用时:3 ms, 在所有 Java 提交中击败了33.87%的用户

内存消耗:38.3 MB, 在所有 Java 提交中击败了16.66%的用户

往K神的代码靠:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Deque<Integer> stack =new ArrayDeque(); //定义辅助栈
        int j = 0;
        for (int elem:pushed) { //pushed里面的每一个元素遍历
            stack.push(elem); //挨个压入
            while (!stack.isEmpty() && stack.peek() == popped[j]) {
                //省掉了第一个判断
                //辅助栈非空,并且栈顶元素为popped目前第一个元素
                //学习.peek方法,而不是还得pop。
                stack.pop();
                j++;
            }
            //循环一次代表找到一个
        }
        return stack.isEmpty(); //跑完循环而且全部出栈,说明正确
    }
}

少了一项判断,时间效率上来了。执行结果:通过

显示详情

执行用时:2 ms, 在所有 Java 提交中击败了95.74%的用户

内存消耗:38.3 MB, 在所有 Java 提交中击败了15.46%的用户

这里的解答与方法四中的第二种解法一样,学习空间效率也更高的解法,不用辅助栈

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int i = 0, j = 0;
        for (int elem:pushed) { //pushed里面的每一个元素遍历
            pushed[i] = (elem); //这一步注释则解答错误
            while (i >= 0 && pushed[i] == popped[j]) {
                //循环成立则说明在pushed中找到了popped中的第一二三个
                j++;
                i--;
                //每找到一个则popped往后,pushed往前
            }
            //没有匹配到则在pushed后面继续找
            i++;
            //循环一次代表找到一个
        }
        return i == 0; //i=0则说明找完了,不等于0则说明没匹配到卡一半了
    }
}

只能说太骚太强了,每一句都是必须的,思路缜密,想学习只能靠记了,看一遍感觉都理解不太了。

执行结果:通过

显示详情

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:38.1 MB, 在所有 Java 提交中击败了64.44%的用户

学习他人:

方法一:

宝石L1 (编辑过)2020-02-28

Java题解 简单明了

判断合不合法,用个栈试一试: 把压栈的元素按顺序压入,当栈顶元素和出栈的第一个元素相同,则将该元素弹出,出栈列表指针后移并继续判断。最后判断出栈列表指针是否指向出栈列表的末尾即可。

    public boolean validateStackSequences(int[] pushed, int[] popped) {

        Deque<Integer> stack = new ArrayDeque();
        int j = 0;
        for (int elem : pushed) {
            stack.push(elem);
            while (j < popped.length && !stack.isEmpty() && stack.peek() == popped[j]) {
                stack.pop();
                j++;
            }
        }
        return j == popped.length;
    }

方法二:

梵_L1 2021-03-14

使用数组代替栈结构,优化了一定空间

    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int len = pushed.length;
        int indexPush =0,indexPop=0;
        int[] mockStack =new int[len];
        int index=0;
        while(indexPush<len&&indexPop<len){
            //入栈
            mockStack[index]=pushed[indexPush++];
            //出栈
            while(indexPop<len&&index>=0&&popped[indexPop]==mockStack[index]){
                index--;
                indexPop++;
            }
            index++;
        }
        return index==0;
    }

方法三:

K神 考虑借用一个辅助栈 stackstack ,模拟 压入 / 弹出操作的排列。根据是否模拟成功,即可得到结果。

入栈操作: 按照压栈序列的顺序执行。
出栈操作: 每次入栈后,循环判断 “栈顶元素 == 弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。

作者:jyd
链接:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/solution/mian-shi-ti-31-zhan-de-ya-ru-dan-chu-xu-lie-mo-n-2/
来源:力扣(LeetCode)

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int num : pushed) {
            stack.push(num); // num 入栈
            while(!stack.isEmpty() && stack.peek() == popped[i]) { // 循环判断与出栈
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();
    }
}

方法四

一个肥宅L1 2020-07-23

O(1) 空间 O(n) 时间 太强了。

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int i = 0, j = 0;
        for (int e : pushed) {
            pushed[i] = e;
            while (i >= 0 && pushed[i] == popped[j]) {
                j++;
                i--;
            }
            i++;
        }
        return i == 0;
    }
}

O(n) 时间 & 空间

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int index = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        for (int e : pushed) {
            stack.push(e);
            while (!stack.isEmpty() && stack.peek() == popped[index]) {
                stack.pop();
                index++;
            }
        }
        return index == popped.length;
    }
}

总结

以上就是本题的内容和学习过程了,不用辅助栈的思路很是巧妙,理解正常的解法目前来说就足够了。

欢迎讨论,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值