栈与队列--面试有关题型

栈与队列–有关题型

第一题:括号匹配问题
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。

解题思路:需要使用栈来完成
1.遍历字符串,如果当前是左括号,就入栈.
2.如果当前是右括号,就拿这个右括号和当前的栈顶元素进行比较,看看是不是匹配的括号.
如果匹配,就把栈顶元素出栈,继续遍历下一个字符.
如果不匹配,就说明当前的字符是非法的.
3.当字符串遍历结束之后,并且栈也同时为空,此时说明整个字符串是一个合法情况.

代码如下:

class Solution {
    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);
                continue;
            }
            //右括号(题目中要求只包含括号,没有其他字符)
            //取栈顶元素和当前的括号匹配.
            //注意,标准库中的Stcak,在针对空栈进行peek时会直接抛异常.
            if (stack.isEmpty()) {
                return false;
            }
            Character top = stack.pop();
            if (top == '(' && c == ')') {
                continue;
            }
            if (top == '[' && c == ']') {
                continue;
            }
            if (top == '{' && c == '}') {
                continue;
            }
            //如果没有触发到上面合法的三种情况,则此时就是非法情况,直接返回false
            return false;
        }
        //循环结束,说明字符串已经遍历完.
        //此时还需要判定一下,栈是否为空.
        if(stack.isEmpty()){
            return true;
        }
        return false;
    }
}

第二题:用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

解题思路:重点在于倒腾.
两个队列A和B
1.使用队列A用来进行入栈操作,使用队列B用来辅助进行倒腾.
2.针对MyStack 进行入栈,就把新元素插入到队列A中,继续再进行入栈,仍然往A中插入.
3.针对MyStack 进行出栈(注意,此时先进先出),对A中的元素进行出队列操作,将最后一个出队列的元素删掉(即不再进入队列B),就完成出栈操作.
4.为了方便下次插入,将A和B调换位置,以保证B始终是辅助进行出栈的队列,A始终是辅助进行入栈的队列.
5.取栈顶元素操作和出栈操作大同小异,即取栈顶元素和出栈的唯一区别就是把A中的最后一个还要再塞回B中.

代码如下

class MyStack {
    private Queue<Integer> A = new LinkedList<>();
    private Queue<Integer> B = new LinkedList<>();
    public MyStack() {

    }
    public void push(int x) {
        //入栈时,直接往A中插入.
        A.offer(x);
    }
    public int pop() {
        //出栈时,把A中的元素往B中倒腾,当A中只剩一个元素的时候
        //最后这个元素就是被删除的元素.
        if(A.isEmpty() && B.isEmpty()){
            //针对空栈的判定.
            //注意,题目要求的方法不是Integer,就无法返回null,只能随便返回一个值.
            return 0;
        }
        while(A.size() > 1){
            int tmp = A.poll();
            B.offer(tmp);
        }
        //当上面的循环结束,此时A中就只剩下一个元素
        //把这个最后的元素作为出栈的结果即可.
        int ret = A.poll();
        //最终完成操作之后,交换A和B,保证下次入栈还是往A中插入.
        swapAB();
        return ret;
    }
    private void swapAB(){
        Queue<Integer> tmp = A;
        A = B;
        B = tmp;
    }
    public int top() {
        //取栈顶元素和出栈的唯一区别
        //在于取栈顶元素时把A中的最后一个还要再塞回B中
        if(A.isEmpty() && B.isEmpty()){
            return 0;
        }
        while(A.size() > 1){
            int tmp = A.poll();
            B.offer(tmp);
        }
        int ret = A.poll();
        B.offer(ret);
        swapAB();
        return ret;
    }
    public boolean empty() {
        return A.isEmpty() && B.isEmpty();
    }
}

第三题:用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾。
int pop() 从队列的开头移除并返回元素。
int peek() 返回队列开头的元素。
boolean empty() 如果队列为空,返回 true ;否则,返回 false。

解题思路:重点在于倒腾.
两个栈A和B
A专门辅助进行入队列
B专门辅助进行出队列
1.A专门辅助进行入队列, B专门辅助进行出队列.
2.针对MyStack 进行入队列,就把新元素插入到A中.
3.针对MyStack 进行出队列,把A中的元素往B中倒腾,当A中只剩一个元素的时候,这个元素就是要被出队列的元素.
注意:此处不用交换A和B
如果继续入队列,仍然是往A中插入,但是往A中插入之前,需要先把B中的元素给倒腾回来.
4.取队首元素操作和出队列操作相同,也是先倒腾到B中,然后取B的栈顶元素即可.

代码如下

class MyQueue {
    Stack<Integer> A =new Stack<>();
    Stack<Integer> B =new Stack<>();
    /** Initialize your data structure here. */
    public MyQueue() {

    }
    public void push(int x) {
        //入队列时,需要先把B中的元素倒腾到A中,再往A中插入新元素.
            while(!B.isEmpty()){
                int tmp = B.pop();
                A.push(tmp);
            }
            A.push(x);
        }
    public int pop() {
        if(A.isEmpty() && B.isEmpty()) {
            return 0;
        }
        //把A中的元素往B中倒腾,剩下的最后一个元素就是要被出队列的元素.
//        while(A.size() > 1) {
//            int tmp = A.pop();
//            B.push(tmp);
//        }
        //此时取到的就是最后一个元素,也就是队首元素.
//        int ret = A.pop();
//        return ret;
        //使用上面的代码,在进行连续多次pop/peek时会存在问题.
        //更优解,先把A的所有元素都倒腾到B中,然后再通过B进行pop.
        while(!A.isEmpty()){
            int tmp = A.pop();
            B.push(tmp);
        }
        //删除B中的元素.
        return B.pop();
    }
    public int peek() {
        if(A.isEmpty() && B.isEmpty()) {
            return 0;
        }
 //       while(A.size() > 1) {
 //           int tmp = A.pop();
 //           B.push(tmp);
 //       }
 //       int ret = A.pop();
        //取队首元素和出队列的唯一区别
        //在于取队首元素时把A中的最后一个还要再倒腾到B中.
 //       B.push(ret);
 //       return ret;
        while(!A.isEmpty()){
            int tmp = A.pop();
            B.push(tmp);
        }
        return B.peek();
    }

第四题
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

解题思路:题目要求以O(1)来得到最小值.
两个栈A和B
B中的内容就是由一系列"当前"的最小值构成.
每次给A中插入元素,都需要拿A的这个元素和B的栈顶进行对比,把最小值入到B中.
后续需要获取最小值,直接从B的栈顶来取.
如果对A出栈,也同步对B出栈,出栈元素后,B的栈顶仍然是A的最小值.

代码如下

class MinStack {
    //创建两个栈.
    Stack<Integer> A = new Stack<>();
    //B里存的就是当前A的最小值.
    Stack<Integer> B = new Stack<>();
    public MinStack() {

    }

    public void push(int x) {
        //先把x插入A中.
        A.push(x);
        //比较x和B的栈顶,看谁小,谁小就插入谁.
        if(B.isEmpty()){
            B.push(x);
            return;
        }
        int min = B.peek();
        if(x < min){
            min = x;
        }
        B.push(min);
    }

    public void pop() {
        if(A.isEmpty()){
            return;
        }
        A.pop();
        B.pop();
    }

    public int top() {
        if(A.isEmpty()){
            return 0;
        }
        return A.peek();
    }

    public int getMin() {
        if(B.isEmpty()){
            return 0;
        }
        return B.peek();
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值