当前位置: 首页 > news >正文

【数据结构】——栈和链表的面试题详解

一、栈的面试题详解

1、20. 有效的括号 - 力扣(LeetCode)

 我们先来列出来括号不匹配的几种情况:

  1. 左右括号不匹配
  2. 右括号多
  3. 左括号多

 括号匹配的情况:

  1. 字符串遍历完成
  2. 栈为空

代码如下:

public boolean isValid(String s) {
        //时间复杂度O(N),空间复杂度O(N)
        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{
                //右括号
                if(stack.empty()){
                    //右括号多
                    return false;
                }
                char top = stack.peek();
                if(ch == ')' && top == '(' || ch == '}' && top == '{' || ch == ']' && top == '['){
                    //说明当前字符是匹配的
                    stack.pop();
                }else{
                    //左右括号不匹配
                    return false;
                }
            }
        }
        if(stack.empty()){
            return true;
        }else{
            return false;
        }
    }

2、150. 逆波兰表达式求值 - 力扣(LeetCode)

 首先我们先来了解一下逆波兰表达式(也叫作后缀表达式):

将这个式子转成逆波兰表达式:a + b * c +  (d * e + f ) * g

  1. 我们先从左到右按照先乘除后加减的顺序进行加括号:( a + (b * c ) )+( ( (d * e) + f ) * g) )
  2. 把括号内的运算符放到对应括号的外面:a b c * + ( ( (d e*  f + g)* +
  3. 再把括号去掉: a  b c  *  +  d e  *  f  + g *  +

完整代码:

public int evalRPN(String[] tokens) {
       Stack<Integer> stack = new Stack<>();
       for(String x : tokens){
           //不是加减乘除
           if(!isOperation(x)){
               stack.push(Integer.parseInt(x));
           }else{
               int num2 = stack.pop();
               int num1 = stack.pop();
               switch(x){
                   case "+":
                    stack.push(num1+num2);
                    break;
                   case "-":
                    stack.push(num1-num2);
                    break;
                   case "*":
                    stack.push(num1*num2);
                    break;
                   case "/":
                    stack.push(num1/num2);
                    break;
               }
           }
       } 
       return stack.pop();
    }
    private boolean isOperation(String opera){
        if(opera.equals("+") || opera.equals("-") || opera.equals("*") || opera.equals("/")){
            return true;
        }else{
            return false;
        }
    }

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

 这道题我们用栈来解决:

  1. 我们可以先定义一个栈用来存储元素,然后定义两个下标 i  j  来遍历push数组和pop数组,
  2. 当push[i]  !=  pop[j]时,将push[i]入栈,i++,j不变,然后在进行比较,
  3. 如果push[i]  ==  pop[j],那就弹出栈顶元素,直到栈为空,说明pop[ ]是该压栈序列的弹出序列:

完整代码:

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

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        if(pushA.length == 0 || popA.length == 0){
            return false;
        }
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for(int i = 0; i < pushA.length; i++){
            //先入栈
            stack.push(pushA[i]);
            //满足条件就弹出栈
            while(j < popA.length && !stack.empty() && stack.peek().equals(popA[j]) ){
                stack.pop();
                j++;
            }
        }  
        return stack.empty();
    }
}

二、队列面试题

1、225. 用队列实现栈 - 力扣(LeetCode)

分析:

  1. 首先我们要知道一个队列是无法实现栈的,所以我们要创建两个队列qu1和qu2
  2. 入栈时,入到不为空的队列中,出栈时,出不为空的队列(size - 1)个,

完整代码:

class MyStack {

    Queue<Integer> queue1;
    Queue<Integer> queue2;
    public int usedSize;
    public MyStack() {
        queue1 = new LinkedList<>() ;
        queue2 = new LinkedList<>();
    }
    //入栈
    public void push(int x) {
        if (!queue1.isEmpty()){
            queue1.offer(x);
        }else if (!queue2.isEmpty()){
            queue2.offer(x);
        }else {
            //qu1和qu2都为空
            queue1.offer(x);
        }
        usedSize++;
    }
    //出栈
    public int pop() {
        if (empty()){
            return -1;
        }
        if (!queue1.isEmpty()){
            int curSize = queue1.size();
            for (int i = 0; i < curSize-1; i++) {
                queue2.offer(queue1.poll());
            }
            usedSize--;
            return queue1.poll();
        }else {
            int curSize = queue2.size();
            for (int i = 0; i < curSize-1; i++) {
                queue1.offer(queue2.poll());
            }
            usedSize--;
            return queue2.poll();
        }
    }
    //peek查看栈顶元素
    public int top() {
        if (empty()){
            return -1;
        }
        if (!queue1.isEmpty()){
            int curSize = queue1.size();
            int ret = -1;
            for (int i = 0; i < curSize; i++) {
                ret = queue1.poll();
                queue2.offer(ret);
            }
            return ret;
        }else {
            int curSize = queue2.size();
            int ret = -1;
            for (int i = 0; i < curSize; i++) {
                ret = queue2.poll();
                queue1.offer(ret);
            }
            return ret;
        }
    }
    //
    public boolean empty() {
        return usedSize == 0;
    }
}

 2、232. 用栈实现队列 - 力扣(LeetCode)

同理也需要用两个栈来模拟实现队列:

class MyQueue {
    Stack<Integer> s1;
    Stack<Integer> s2;
    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    public void push(int x) {
        s1.push(x);
    }
    public int pop() {
        if (empty()){
            return -1;
        }
        if (s2.empty()){
            //需要把s2里面的元素全部倒过来
            while (!s1.empty()){
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
    public int peek() {
        if (empty()){
            return -1;
        }
        if (s2.empty()){
            //需要把s2里面的元素全部倒过来
            while (!s1.empty()){
                s2.push(s1.pop());
            }
        }
        return s2.peek();
    }
    public boolean empty() {
        return s1.empty() && s2.empty();
    }
}

3、155. 最小栈 - 力扣(LeetCode) 

  1. 这个题的关键就是需要多创建一个栈用来存储相对小的值
  2. 当我们需要出栈的时候,除了出普通栈的元素之外,每次出的时候,都要和最小栈的栈顶元素进行比较如果相等,那么最小站=栈当中也要出栈,这样才能保证每次获取最小值的时候,正好在最小栈的栈顶!
  3. 最后得到最小值的时候就只需要弹出最小栈的栈顶元素:

class MinStack {
    private Stack<Integer> s;//普通栈
    private Stack<Integer> minStack;//维护当前栈的最小值

    public MinStack() {
        s = new Stack<>();
        minStack = new Stack<>();
    }

    /**
     * 入栈
     * @param val
     */
    public void push(int val) {
        s.push(val);// 普通栈 必须放
        if (minStack.empty()){
            //也存一份到最小栈中
            minStack.push(val);
        }else {
            int peekVal = minStack.peek();
            if (val <= peekVal){
                minStack.push(val);
            }
        }
    }

    /**
     * 出栈
     */
    public void pop() {
//        if (s.pop().equals(minStack.peek())){
//            minStack.pop();
//        }
        if (!s.empty()){
            int popVal = s.pop();
            int peekValMinS = minStack.peek();
            if (peekValMinS == popVal){
                minStack.pop();
            }
        }
    }
    
    public int top() {
        if (!s.empty()){
            return s.peek();
        }
        return -1;
    }
    
    public int getMin() {
        if (!minStack.empty()){
            return minStack.peek();
        }
        return -1;
    }
}

相关文章:

  • 如何从 apt-get 升级中排除特定软件包
  • C++/Python:罗德里格斯旋转矩阵
  • c++征途 --- STL初识
  • 学习编程的第二十三天
  • 上交所技术——2020春招应用开发工程师(Java)笔试
  • 猿创征文|时间序列分析算法之二次指数平滑法和三次指数平滑法详解+Python代码实现
  • 基于人工兔优化算法的函数寻优和工程优化
  • 网络安全无小事, 所有艾思运维人员, 在nginx中必须对thinkphp的目录做以下安全设置, 未尽目录请自行添加
  • Shiro 权限绕过漏洞(CVE-2020-1957)
  • 【python脚本】用于生成简单握手接口与自测环境的gen_uvm_agent脚本
  • Java多线程下——各类锁的详解
  • vue——VM对象和基础指令
  • 手把手带你刷好题(牛客刷题②)
  • 【web-攻击用户】(9.7.1)本地隐私攻击:持久性cookie、缓存Web内容、浏览历史记录、Flash本地共享对象……
  • Linux shell 内建命令
  • ➹使用webpack配置多页面应用(MPA)
  • es6--symbol
  • jQuery(一)
  • LeetCode算法系列_0891_子序列宽度之和
  • Node 版本管理
  • php的插入排序,通过双层for循环
  • python学习笔记-类对象的信息
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • React Transition Group -- Transition 组件
  • 从setTimeout-setInterval看JS线程
  • 大型网站性能监测、分析与优化常见问题QA
  • 对JS继承的一点思考
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 基于web的全景—— Pannellum小试
  • 前端技术周刊 2019-02-11 Serverless
  • 如何合理的规划jvm性能调优
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 数据库巡检项
  • # 透过事物看本质的能力怎么培养?
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (2)(2.10) LTM telemetry
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (C语言)字符分类函数
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (差分)胡桃爱原石
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)Linux下编译安装log4cxx
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .axf 转化 .bin文件 的方法
  • .NET MVC第三章、三种传值方式
  • ??eclipse的安装配置问题!??
  • @Controller和@RestController的区别?
  • [.NET]桃源网络硬盘 v7.4
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——