栈和队列OJ题记录

栈的压入与弹出

1、描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
在这里插入图片描述
2、思路: 遍历popped数组,当popped[i] 等于当前栈中的栈顶元素时,说明此时需要出栈。是用if还是while循环?如果此时popped = [4,3,2,1,5],弹出前一个时,后一个仍然满足弹出条件,所以要使用while循环。还有一个问题,程序如何判断popped数组是不是合理的数组?当将pushed数组遍历完毕,所有元素均入栈之后,最终在根据popped数组判断是否要将栈顶元素弹出时,如果最终栈非null,则对应的popped数组一定不匹配。
3、代码实现

public class Offer31_IsPopOrder {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        //标识当前popA数组处理到那个元素
        int i  = 0;
        Stack<Integer> stack = new Stack<>();
        //将pushA数组中的元素依次入栈
        for (int val: pushA) {
            stack.push(val);
            while (!stack.isEmpty() && stack.peek() == popA[i]){
                //当栈顶的值和popA中的值相等,弹出
                stack.pop();
                i++;
            }
        }
        //遍历完整个数组还没弹空,则非法
        return stack.isEmpty();
    }
}

有效的括号

1、描述:
在这里插入图片描述
2、思路: 用栈解决这个问题主要有点:只有碰到左括号才入栈;只要碰到右括号,在栈为非null的前提下,弹出栈顶元素,判断是否有匹配的左括号。
3、代码实现

public class Num20_IsValid {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(c == '(' || c == '{' || c == '['){
                //碰到左括号直接入栈
                stack.push(c);
            }else{
                //此时c为右括号,没有对应的左括号让他闭合
                if(stack.isEmpty()){
                    //找到反例
                    return false;
                }
                char top = stack.pop();
                if(c == ')' && top!='('){
                    return false;
                }
                if(c == '}' && top!='{'){
                    return false;
                }
                if(c == ']' && top!='['){
                    return false;
                }
            }
        }
        //此时没有相应的右括号让他闭合
        return stack.isEmpty();
    }
}

最小栈

1、描述:
在这里插入图片描述
在这里插入图片描述

2、思路: 这个题目的核心是getMin方法的实现,要求要在常数时间内检索到最小元素,所以需要想一个办法将最小值每次都放在栈顶,但是还不能影响top方法。我们采用双栈思路,引入另一个栈s2,每次存放当前s1栈中的最小值,当调用getMin方法时,我们从s2中获取,其他的方法在s1上操作。
在这里插入图片描述
3、代码实现

public class MinStack {
    private Stack<Integer> s1;
    private Stack<Integer> s2;
    public  MinStack() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    //双栈
    public void push(int val) {
        //先将val压入s1
        s1.push(val);
        //如果s2为空,将同样的元素压入s2
        if(s2.isEmpty()){
            s2.push(val);
        }else {
            //此时s2不为空,先获取s2顶部的元素
            int tempMin = s2.peek();
            //比较要压入的元素与s2顶部元素的大小
            //在s2中压入较小的元素,使其和s1中元素个数保持一致
            if(val<tempMin){
                s2.push(val);
            }else{
                s2.push(tempMin);
            }
        }
    }

    public void pop() {
        s1.pop();
        s2.pop();
    }
    public int top() {
        return s1.peek();
    }
    public int getMin() {
        return s2.peek();
    }
}

逆波兰表达式求值

1、描述:
在这里插入图片描述
2、思路: 要做这道题,首先需要知道什么是逆波兰表达式。百度百科的定义:
在这里插入图片描述
同样借助栈,扫描整个字符串,当碰到数字时,将数字压入栈中,一旦碰到运算符,将栈中元素连弹两次,先弹出的是除数/减数,后弹出的是被除数/被减数,然后将运算结果继续压入栈中,最后扫描完整个字符串,此时栈顶元素就是最终的i计算结果。
3、代码实现

public class Num150_EvalRPN {
    public int evalRPN(String[] tokens) {
        Stack<Integer> s1 = new Stack<>();
        //遍历整个字符串,判断是数字就压入
        for ( String str: tokens) {
            if(isNum(str)){
                //将字符串转成数字,碰到数字就压入栈
                s1.push(Integer.parseInt(str));
            }else{
                //此时不数字,碰到的是运算符
                //从栈中连弹两个
                //最先弹出的是被除数或被减数
                int num1 = s1.pop();
                //后弹出的是除数或减数
                int num2 = s1.pop();
                //计算
                int result = 0;
                switch (str){
                    case "+" :
                        result = num2 + num1;
                        break;
                    case "-" :
                        result = num2 - num1;
                        break;
                    case "*" :
                        result = num2 * num1;
                        break;
                    default:
                        result = num2 / num1;
                }
                //把计算结果再塞入栈中
                s1.push(result);
            }
        }
        //返回栈顶元素
        return s1.peek();
    }
     //辨别是字符还是数字
    private boolean isNum(String str){
        try {
            //将字符串转换为数字
            Integer.parseInt(str);
            //没报错返回true
            return true;
        }catch (NumberFormatException e){
            return false;
        }
    }
}

队列

双队列实现栈

1、描述:
在这里插入图片描述
2、思路:
(1)新元素先入q2
(2)交换q1q2引用,使得q1永远是存储元素的队列;
(3)新元素再入q2之后,将q1中的元素依次出队再入q2
(4)交换q1q2引用,重复以上步骤。
在这里插入图片描述
3、代码实现

public class Num225_MystackByTwoQueue {
    //定义两个队列
    //q1永远是储存元素的队列
    private Queue<Integer> q1 = new LinkedList<>();
    //q2永远保存新元素
    private Queue<Integer> q2 = new LinkedList<>();

    public void push(int x) {
        //新元素入q2;
        q2.offer(x);
        //将q1的所以元素依次出队再入q2
        while (!q1.isEmpty()){
            q2.offer(q1.poll());
        }
        //交换q1和q2
        Queue<Integer> tmp = q1;
        q1 = q2;
        q2 = tmp;
    }

    public int pop() {
        return q1.poll();

    }
    public int top() {
        return q1.peek();
    }

    public boolean empty() {
        return q1.isEmpty();
    }
}

一个队列实现栈

1、思路:
在这里插入图片描述
2、代码实现

public class Num225_MystackByOneQueue {
    private Queue<Integer> queue = new LinkedList<>();
    public void push(int x) {
        //暂存一下当前队列中的元素个数
        int size = queue.size();
        //新元素入队
        queue.offer(x);
        //此时旧元素先出队再入队
        for (int i = 0; i < size; i++) {
            queue.offer(queue.poll());
        }
    }

    public int pop() {
        return queue.poll();
    }

    public int top() {
        return queue.peek();
    }

    public boolean empty() {
        return queue.isEmpty();
    }
}

双栈实现队列

1、描述:
在这里插入图片描述
2、思路: 在队列中,新元素在队尾,所以类比到栈中,要让新元素在栈底而不是栈顶。在空栈中插入一定是栈底~。
在这里插入图片描述
3、代码实现

public class Num232_MyqueueByTwoStack {
    //s1永远是存储元素的栈
    private Stack<Integer> s1 = new Stack<>();
    private  Stack<Integer> s2 = new Stack<>();
    public void push(int x) {
        //先将s1中的所有元素依次压入S2中
        while (!s1.isEmpty()){
            s2.push(s1.pop());
        }
        //此时s1空出,栈底存放新元素,就是队尾
        s1.push(x);
        //再将s2中的所有元素依次弹出压入s1中
        while (!s2.isEmpty()){
            s1.push(s2.pop());
        }
    }

    public int pop() {
        return s1.pop();
    }

    public int peek() {
        return s1.peek();
    }

    public boolean empty() {
        return s1.isEmpty();
    }
}

继续加油努力!!!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值