【数据结构】栈和队列面试题总结(持续更新中...)

目录

一、栈相关基础概念

二、队列相关基础概念

三、OJ题

3.1 不可能的出栈顺序

3.2 中缀表达式

3.3 括号匹配

3.4 逆波兰表达式求值

3.5 出栈入栈次序匹配

3.6 循环队列

3.7 用队列实现栈

3.8 用栈实现队列

3.9 最小栈


一、栈相关基础概念

① 先进先入。不是所有进完才可以出,入的同时也可以出

②用数组实现栈:入栈和出栈的时间复杂度是O(1)

③用单链表实现栈:

头插法: 入栈和出栈 O(1)

尾插法:入栈和出栈 O(n)

所以用单链表实现栈时一定要头入头出

④方法  push、peek、pop、size、empty

二、队列相关基础概念

① 队尾进,队头出。底层是个双向链表。

②Queue是个接口,在实例化时必须实例化LinkedList的对象。

        Queue<Integer> q = new LinkedList<>();

③用单链表实现队列  ok

④ 用数组实现队列 。必须使用循环数组。后面3.6有代码实现逻辑。

④方法  offer、poll、peek、size、isEmpty

三、OJ题

3.1 不可能的出栈顺序

核心:入的时候同时可以出

3.2 中缀表达式

中缀转后缀:按照自己的理解,从左往右加括号,先乘除后加减。再逐步将运算符移到括号后,移

                        掉所有的(),就是rug

计算中缀表达式的值:遇见数字入栈,遇到运算符就从栈出两个元素。先出的放在运算符的后面,后出栈的放在运算符前面。将计算结果再入栈。

3.3 括号匹配

 OJ链接:20. 有效的括号 - 力扣(LeetCode)

实现代码:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0 ;i<s.length();i++){
            char ch = s.charAt(i);
            // 遇见左括号就入栈,注意是单引号
            if(ch == '[' || ch == '{' || ch == '('){
                stack.push(ch);
            }else{
                // 否则,就与栈顶元素进行比较
                // 如果栈是空的,并且遇见的是右括号,直接返回false
                // 判断栈空 不能使用stack==null
                if(stack.isEmpty()){
                    return false;
                }else{
                    char peek = stack.pop();
                    if( (peek == '[' && ch == ']') || (peek == '{' && ch == '}') || (peek == '(' && ch ==')')){
                        continue;
                    }else{
                        return false;
                    }
                }
            }
        }
        if(stack.isEmpty()){
            return true;
        }else{
            return false;
        }
    }
}

3.4 逆波兰表达式求值

 OJ链接:150. 逆波兰表达式求值 - 力扣(LeetCode)

实现代码:

class Solution {

    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        HashSet<String> set = new HashSet<>();
        set.add("+");
        set.add("-");
        set.add("*");
        set.add("/");
        for(String str:tokens){
            // 如果遇见的是不是运算符,是数字,就入栈
            if(!set.contains(str)){
                stack.push(Integer.parseInt(str));
            }else{
                // 遇见运算符,就弹出两个数字
                int back = stack.pop();
                int front = stack.pop();
                HashMap<String,Integer> hashMap = new HashMap<>();
                hashMap.put("+",front+back);
                hashMap.put("-",front-back);
                hashMap.put("*",front*back);
                //  注意:back有可能为 0 
                if(back != 0){
                    hashMap.put("/",front/back);
                }
//计算结果,将结果入栈
                int result = hashMap.get(str);
                stack.push(result);
            }
        }
        return stack.peek();
    }
}

3.5 出栈入栈次序匹配

 OJ链接:栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)

 解题思路:

要点1:定义一个pos,记录popA数组中元素的位置。

要点2:遍历pushA,依次将pushA中的元素入栈,判断栈顶元素和popA中的元素是否相同,相同就出栈,并观察popA中的下一个元素是否和新栈顶元素相等。如果不相等,入栈pushA的下一个元素

实现代码:

import java.util.*;
import java.util.ArrayList;

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        Stack<Integer> stack1 = new Stack();
        int pos = 0;
        for(int i=0;i<pushA.length;i++){
            stack1.push(pushA[i]);
            while(!stack1.isEmpty() && stack1.peek() == popA[pos]){
                stack1.pop();
                pos++;
            }
        }
        if(stack1.empty()){
            return true;
        }
        return false;
    }
}

3.6 循环队列

 OJ链接:622. 设计循环队列 - 力扣(LeetCode)

 解题思路:

要点1:为了区分队列空和满,约定:

        rear指向数组最后一个元素的下一个位置,下一次添加数据,可以直接往rear位置上放

        front == rear 队列空

        rear的下一个元素是front,队列满了。(rear+1)%elem.length

要点2:返回队列顶部元素,返回front所在位置元素,front向前移。为了保证front可以从3移到1,front=(front+1)%elem.length

要点3:返回队列最后一个元素。如果rear=0,返回elem[elem.length-1].如果rear不为0,就返回elem[rear-1]

实现代码:

class MyCircularQueue {

    private int[] elem;
    private int front;
    private int rear;

    public MyCircularQueue(int k) {
        elem = new int[k+1];
    }
    
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }
        if(isEmpty()){
            elem[0] = value;
            front = 0;
            rear = 1;
            return true;
        }
        elem[rear] = value;
        rear = (rear+1) % elem.length;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front = (front+1) % elem.length;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return elem[front];

    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        if(rear == 0){
            return elem[elem.length-1];
        }
        return elem[rear-1];

    }
    
    public boolean isEmpty() {
        return rear == front;

    }
    
    public boolean isFull() {
        if((rear+1)%elem.length == front){
            return true;
        }
        return false;

    }
}

3.7 用队列实现栈

 OJ链接:225. 用队列实现栈 - 力扣(LeetCode)

解题思路:

要点1:有两个队列

要点2:第一次放push数据时,默认放到队列1中

要点3:添加元素时,添加到不为空的队列中,这样才能保证顺序

要点4:出栈—》获得栈顶元素—》栈后入先出—》弹出最后一个入栈的元素

因此,需要找出最后一个入队列的元素。将队列的前n-1个元素,放到另外一个队列中,剩下的就是最后一个入队列的元素

实现代码:

class MyStack {

    private Queue<Integer> qu1;
    private Queue<Integer> qu2;

    public MyStack() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    
    public void push(int x) {
        // 如果队列2是空的,就往队列1里面放。原因:只有放在不为空的队列中顺序才不会乱
        if(qu2.isEmpty()){
            qu1.offer(x);
        }else{
            qu2.offer(x);
        }
        
    }
    
    public int pop() {
        if(empty()){
            return -1;
        }
        if(qu1.isEmpty()){
            // 队列2不为空,队列先进先出,将队列前size-1个元素放到队列1中,剩下的最后一个元素就是最后入队列的,也就是栈的第一个元素,将其返回
            int size = qu2.size();
            while(size > 1){
                qu1.offer(qu2.poll());
                size--;
            }
            int result = qu2.poll();
            return result;
        }
        if(qu2.isEmpty()){
            int size = qu1.size();
            while(size > 1){
                qu2.offer(qu1.poll());
                size--;
            }
            int result = qu1.poll();
            return result;
        }
        return -1;
    }
    public int top() {
        if(empty()){
            return -1;
        }
        if(qu1.isEmpty()){
            int size = qu2.size();
            while(size > 1){
                qu1.offer(qu2.poll());
                size--;
            }
            int result = qu2.poll();
            qu1.offer(result);
            return result;
        }
        if(qu2.isEmpty()){
            int size = qu1.size();
            while(size > 1){
                qu2.offer(qu1.poll());
                size--;
            }
            int result = qu1.poll();
            qu2.offer(result);
            return result;
        }
        return -1;

    }
    
    public boolean empty() {
        return qu1.isEmpty()&&qu2.isEmpty();
    }
}

3.8 用栈实现队列

 OJ链接:232. 用栈实现队列 - 力扣(LeetCode)

 解题思路:

要点1:有两个栈。存数据都存到栈1中,取数据都从栈2中取。

要点2:取数据时,如果栈2是空的,就把栈1中的元素全放到栈2中。再从栈2中取。

实现代码:

class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    public MyQueue() {
        stack1 = new Stack();
        stack2 = new Stack();
    }
    
    public void push(int x) {
        stack1.push(x);
    }
    
    public int pop() {
        if(empty()){
            return -1;
        }
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
    
    public int peek() {
        if(empty()){
            return -1;
        }
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();

    }
    
    public boolean empty() {
        return stack1.empty()&&stack2.empty();

    }
}

3.9 最小栈

 OJ链接:155. 最小栈 - 力扣(LeetCode)

 解题思路:

要点1:创建两个栈。一个栈存放所有的元素,另外一个栈存放栈中最小的元素

要点2:第一次push数据,数据存放在两个栈中

要点3:之后存放数据,该数据小于等于最小栈的栈顶元素,才能存放到最小栈和stack中。否则,就只能存放到stack中

实现代码:

class MinStack {
    public Stack<Integer> stack;
    public Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack();
        minStack = new Stack();
    }
    
    public void push(int val) {
        // 如果第一次放元素,往stack和minStack里都放
        if(stack.empty() && minStack.empty()){
            stack.push(val);
            minStack.push(val);
            return;
        }
        // 如果存放的数据比minStack元素小,该元素同时放到两个栈中
        if(val <= minStack.peek()){
            stack.push(val);
            minStack.push(val);
            return;
        }else{
            // 否则,就只往stack中放
            stack.push(val);
            return;
        }
    }
    
    public void pop() {
        int peek = stack.pop();
        if(peek == minStack.peek()){
            minStack.pop();
        }
    }
    
    public int top() {
        if(stack.empty()){
            return -1;
        }
        return stack.peek();

    }
    
    public int getMin() {
        if(minStack.empty()){
            return -1;
        }
        return minStack.peek();

    }
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘减减

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值