栈的实现及相关OJ题

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习!

欢迎志同道合的朋友一起加油喔🦾🦾🦾
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心


目录

1. 什么是栈?(Stack)

2. 栈的使用

3. 模拟实现一个栈

3.1 构造方法和成员属性

3.2 push 方法

3.3 pop 方法

3.4 peek 方法

3.5 empty 方法

4.栈相关的OJ题

   4.1 有效的括号

  4.2 栈的压入弹出序列

  4.3 逆波兰(后缀)表达式求值

  4.4 最小栈



1. 什么是栈?(Stack)

 栈是一种数据结构,是操作受限制的线性表(先进后出),它只能在固定的一端进行插入和删除操作,进行数据插入和删除的一端为栈顶,另一端为栈底,按存储方式分为顺序栈(更好实现)和链式栈。

压栈:栈的插入操作叫做进栈/压栈/入栈。入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

2. 栈的使用

方法功能说明
Stack()构造一个空栈
E push(E e)将e入栈并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素的个数
boolean empty()检测栈是否为空

  ●顺序栈:Deque接口+实现类ArrayDeque

Deque<Integer> deque = new ArrayDeque<>();//顺序栈

 ●链式栈:Deque接口+实现类LinkedList

Deque<Integer> deque1 = new LinkedList<>();//链式栈

   栈的使用建议使用上面两种方式,不建议使用Stack

3. 模拟实现一个栈

3.1 构造方法和成员属性

public class MyStack {
    private int[] elem; //存放数据的数组
    private int size; //有效元素个数
    private static final int DEFAULT_CAPACITY = 10; //约定好的默认容量
 
    public MyStack() {
        this.elem = new int[DEFAULT_CAPACITY];
        this.size = 0;
    }
}

有了顺序表和链表的学习,再次学习栈是很轻松的,但是在源码中,开辟空间是在 push 中开辟的,跟顺序表类似的。

3.2 push 方法

// 压栈
public int push(int data) {
    // 判断是否需要增容
    if (this.size == this.elem.length) {
        this.elem = Arrays.copyOf(this.elem, this.size * 2);
    }
    // 压栈只能往栈顶压栈
    this.elem[this.size++] = data;
    return data;
}

在实现push方法要注意,栈扩容的问题,因为我们底层使用的是数组,所以可以用 Arrays.copyOf方法进行扩容。 

3.3 pop 方法

// 出栈
public int pop() {
    // 判断栈是否为null
    if (this.size == 0) {
        throw new MyStackEmptyException("栈为空!");// 自定义异常
    }
    return this.elem[--this.size];
}

在出栈方法中,如果栈为null的情况是不能进行出栈的,也就是有效元素个数size为0的情况,这里博主是直接抛出了一个自定义异常。在返回值的地方也要注意,出栈后栈的元素会减少一个,但我们只需要设置有效数据减一个即可,就像计算机中的删除一样,本质是将数据设置成无效,有新的数据可以直接覆盖。

3.4 peek 方法

// 查看栈顶元素
public int peek() {
    // 判断栈是否为null
    if (this.size == 0) {
        throw new MyStackEmptyException("栈为空!"); //自定义异常
    }
    return this.elem[this.size - 1];
}

peek方法与pop方法相差无几,需要注意的是在返回栈顶元素的时候不要使有效数据个数减少了就像。

3.5 empty 方法

// 判断栈是否为空
public boolean empty() {
    return this.size == 0;
}

4.栈相关的OJ题

   4.1 有效的括号

        ●题目展示

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

       ● 写题思路:

           1) 新建一个栈存左括号,得到对应右括号出左括号,这次匹配成功,继续匹配

           2) 只要左括号的栈为空,且给定字符串还没遍历完,那就代表右括号多了

           3) 给定字符串遍历完了,但是存左括号的栈还有剩余的左括号,那么就是左括号多了

           4) 只要给定字符串遍历完毕,且存左括号的栈无剩余,则为有效括号。

        ● 图示

       ● 实现代码:

class Solution {
    public boolean isValid(String s) {
       Deque<Character> leftStack = new ArrayDeque();
       for(int i = 0; i < s.length(); i++) {
           char ch = s.charAt(i);
           if(ch == '(' || ch == '[' || ch == '{') {
               leftStack.push(ch);
           }else {
               //如果栈中无左括号,又得到了一个右括号,则无效
               if(leftStack.isEmpty()) { //多余的右括号
                   return false;
               }
               //ch为字符串中得到的右括号,ch2为栈中的左括号
               char ch2 = leftStack.peek();
               if(ch == ')' && ch2 == '(' || ch == ']' && ch2 == '[' || ch == '}' && ch2 == '{') {
                   //出栈
                   leftStack.pop();
               }else {
                   return false;//不匹配
               }
           }
       }
       if(!leftStack.isEmpty()) { //还有多余的左括号
           return false;
       }
       return true;
    }
}

  4.2 栈的压入弹出序列

        ● 题目展示


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

       ● 写题思路:

           1) 新建一个栈,根据给定的出栈序列依次进行匹配。

           2) 只要不等于出栈序列的数字,就一直遍历入栈序列入栈

           3) 等于出栈序列的数字后,直接出栈,只要等于出栈序列的数字,该栈就一直出栈,直到不等于结束出栈,继续遍历给定的入栈序列进行入栈。

           4) 重复该操作直到遍历完入栈序列,最后这个栈如果为空,则匹配成功,反之则匹配失败

        ● 图示

         ● 实现代码:

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      Stack<Integer> stack = new Stack<>();
          int j = 0;
          for(int i = 0;i < n;i++){
            stack.push(pushA[j]);
            //此处用equals是因为Integer值的取值范围在-128~127
            while(j < pop.length && (stack.isEmpty()||stack.peek().equals(popA[i])){
                stack.pop();
                j++;
            }
        return stack.empty();
    }
}

  4.3 逆波兰(后缀)表达式求值

         ● 题目展示


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

       ● 写题思路:

          1) 准备中间栈遍历给定后缀表达式,遇到操作数则入中间栈

          2) 遇到操作符则出栈两个操作数进行运算,并将运算结果入栈

          3) 直到后缀表达式遍历完毕,栈中最后一个元素值则为计算结果

        ● 知识普及

         在讲解这个题之前给大家普及一点知识,我们平时的算术表达式中,运算符总是出现在两个操作数之间,例如 5 * (7 - 2 * 3) + 8 / 2 ,这种形式叫做中缀表达式,而我们的逆波兰表达式又叫后缀表达式,那什么是后缀表达式呢???

我们把中缀表达式的运算符移动到自己所在的括号的右括号的右边,然后再去括号,这就是逆波兰表达式,,,那这个东西该怎么计算呢??? 

       ● 实现代码:

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> stack = new ArrayDeque<Integer>(); //存操作数
        for(int i = 0; i < tokens.length; i++) {
            String ch = tokens[i];
            if(!isOperators(ch)) {
                stack.push(Integer.parseInt(ch));
            }else {
                int num1 = stack.pop();//出两个操作数
                int num2 = stack.pop();
                int result = 0; //计算结果  
                switch(ch) {
                    case "+":
                    result = num1 +num2;
                    break;
                    case "-":
                    result = num2 - num1;
                    break;
                    case "*":
                    result = num1 * num2;
                    break;
                    case "/":
                    result = num2 / num1;
                    break;
                }
                //结果入栈
                stack.push(result);
            }
        }
        return stack.pop();
    }
 
    //判断是否为操作符
    public boolean isOperators(String s) {
        return s.equals("+") || s.equals("*") || s.equals("-") || s.equals("/");
    }
}

  4.4 最小栈

          ● 题目展示

         ● 写题链接:力扣

         ● 写题思路:题目的目的是想让我们在O(1)时间复杂度内拿到栈的最小值,所以这里我们不能去遍历栈,而是需要用到两个栈,下面用画图的形式分析一下如何做到:

         ● 实现代码:

class MinStack {
    private Stack<Integer> stack1;
    private Stack<Integer> MinStack;
 
    public MinStack() {
        stack1 = new Stack<>();
        MinStack = new Stack<>();
    }
 
    public void push(int val) {
        stack1.push(val);
        if(MinStack.empty()) {
            MinStack.push(val);
        } else {
            if(val <= MinStack.peek()) {
                MinStack.push(val);
            }
        }
    }
    //题目规定了栈不为空,所以这里没判断
    public void pop() {
        int tmp = stack1.pop();
        if(tmp == MinStack.peek()) {
            MinStack.pop();
        }
    }
    //题目规定了栈不为空
    public int top() {
        return stack1.peek();
    }
 
    public int getMin() {
        return MinStack.peek();
    }
}

5. 栈,虚拟机栈,栈帧的区别

栈:一种后进先出的数据结构,继承自Vector

虚拟机栈:具有特殊作用的一块内存空间。栈区:是线程私有的,存放的是函数调用相关信息,主要是栈帧,它是按照数据结构中栈的特性来实现的

栈帧:一种结构,与函数调用相关。内部:局部变量表,操作数栈。每个方法运行时JVM会创建一个栈帧,然后将栈帧压到虚拟机栈中,调用结束时,该方法对应的栈帧会从虚拟机栈中出栈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/11695.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

再摘一枚重要奖项!腾讯安全获得云安全联盟CSA 2022安全金盾奖

4月13日&#xff0c;第六届云安全联盟大中华区大会&#xff08;CSA GCR Congress&#xff09;在上海举办&#xff0c;大会由联合国数字安全联盟、上海市经济和信息化委员会、上海市委网络安全和信息化委员会办公室、上海市普陀区人民政府指导&#xff0c;云安全联盟大中华区主办…

vue面试题2023

1.$route和$router的区别? routes : 数组。 路由匹配规则 router &#xff1a; 对象。 路由对象 $router &#xff1a; 对象。 用于跳转路由 和 传递参数 $route &#xff1a;对象。 用于接收路由跳转参数 1.Vue的生命周期方法有哪些&#xff1f; - beforeCreate 初始化实…

【产品应用】一体化步进伺服电机在高速异形插件机的应用

随着科技的不断发展&#xff0c;自动化生产设备在各个行业中得到了广泛的应用。高速异形插件机作为自动化生产设备中的一种&#xff0c;其核心部件之一就是一体化步进伺服电机。本文将详细介绍一体化步进伺服电机在高速异形插件机中的应用。 01.设备简介 高速异形插件机是一种…

用智能手机拍的模糊照片怎么办?学会这个技巧让它变得清晰

智能手机的相机功能越来越强大&#xff0c;但有时候我们还是会拍出一些模糊的照片。这可能是因为手抖或者光线不足等原因导致的。但不要担心&#xff0c;有一些简单的技巧可以帮助您将模糊的照片变得更加清晰。 1.稳定手机 拍摄清晰照片的第一步是确保相机保持稳定。拍照时最…

【CSS】课程网站 Banner 制作 ② ( Banner 栏版心盒子测量 | Banner 版心盒子模型左侧导航栏代码示例 )

文章目录一、Banner 栏版心盒子测量1、测量版心元素尺寸2、课程表测量二、Banner 版心盒子模型左侧导航栏代码示例1、HTML 标签结构2、CSS 样式3、展示效果一、Banner 栏版心盒子测量 1、测量版心元素尺寸 拉四条辅助线 , 将版心包起来 , 可以测量 Banner 条版心的尺寸为 1200 …

Cacti监控远程linux机器配置(被监控端)

一、被监控机安装snmp yum -y install snmp二、被监控机的配置 vi /etc/snmp/snmpd.conf做以下更改&#xff1a; 1、找到com2sec notConfigUser default public 改为&#xff1a;com2sec notConfigUser 192.168.1.1(改成监控服务器的ip) public 2、找到acce…

Pandas入门实践3 -数据可视化

人类大脑擅长于在数据的视觉表现中寻找模式;因此在这一节中&#xff0c;我们将学习如何使用pandas沿着Matplotlib和Seaborn库来可视化数据&#xff0c;以获得更多的特性。我们将创建各种可视化&#xff0c;帮助我们更好地理解数据。 使用pandas绘图 我们可以使用plot()方法创…

【linux】Ubuntu aarch64编译安装RXTX进行串口通信

目录1.下载RXTX2.源码下载方式一&#xff1a;方式二&#xff1a;3. 编译源码4.编译源码时遇到的问题问题1&#xff1a;./configure command not found问题2&#xff1a;error: UTS_RELEASE undeclared问题3&#xff1a;libtool: install: armv6l-unknown-linux-gnu/librxtxRS48…

【ZUUL2踩坑】题一:Ribbon集成动态properties存在的原生风险

目录 一、问题背景 二、问题分析 1、配置文件空档期的问题 一、问题背景 JAVA的Properties工具有两种写配置文件的方式&#xff0c;一种是覆盖&#xff0c;一种是追加。 但是动态配置文件一般需要进行创建或更新&#xff0c;不会选择追加内容&#xff0c;所以只能选择进行配…

docker目录映射

docker 常用命令 docker ps // 查看所有正在运行容器 docker stop containerId // containerId 是容器的ID docker ps -a // 查看所有容器 $ docker ps -a -q // 查看所有容器ID docker stop $(docker ps -a -q) // stop停止所有容器 docker rm $(docker ps -a -q) // remove删…

replugin宿主与插件通信小结

近来replugin开发中遇到宿主和插件间需要通信的情形&#xff0c;思来只有进程间通信(IPC)才是比较好的宿主与插件的通信方式。而Android进程间通信主要有2种方式&#xff1a;Messenger和AIDL。 AIDL&#xff08;Android Interface Definition Language&#xff09;是Android接…

ChatGPT团队中,3个清华学霸,1个北大学霸,共9位华人

众所周知&#xff0c;美国硅谷其实有着众多的华人&#xff0c;哪怕是芯片领域&#xff0c;华为也有着一席之地&#xff0c;比如AMD 的 CEO 苏姿丰、Nvidia 的 CEO 黄仁勋 都是华人。 还有更多的美国著名的科技企业中&#xff0c;都有着华人的身影&#xff0c;这些华人&#xff…

Java入坑之类的派生与继承

一、继承 1.1继承的概念 Java中的继承&#xff1a;子类就是享有父类的属性和方法&#xff0c;并且还存在一定的属性和方法的扩展。 Subclass&#xff0c;从另一个类派生出的类&#xff0c;称为子类(派生类&#xff0c;扩展类等) Superclass&#xff0c;派生子类的类&#xff…

3.5 函数的极值与最大值和最小值

学习目标&#xff1a; 我要学习函数的极值、最大值和最小值&#xff0c;我会采取以下几个步骤&#xff1a; 理解基本概念&#xff1a;首先&#xff0c;我会理解函数的极值、最大值和最小值的概念。例如&#xff0c;我会学习函数在特定区间内的最高点和最低点&#xff0c;并且理…

( “树” 之 DFS) 104. 二叉树的最大深度 ——【Leetcode每日一题】

104. 二叉树的最大深度 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c; 返回它的最大深度 3 。 思路&am…

激光和相机的标定

一、手动标定 代码工程&#xff1a;GitHub - Livox-SDK/livox_camera_lidar_calibration: Calibrate the extrinsic parameters between Livox LiDAR and camera 这是Livox提供的手动校准Livox雷达和相机之间外参的方法&#xff0c;并在Mid-40&#xff0c;Horizon和Tele-15上进…

ReactNative入门

React基本用法&#xff1a; react与js不同的点在于 react使用的是虚拟DOM js是真实DOM 作用&#xff1a;当有新的数据填充 可以复用之前的&#xff0c;而js需要整体重新渲染 创建虚拟DOM还可以使用jsx语法直接声明&#xff1a; 注意要用babel标签将jsx转化为js 但是建议采用j…

图解并用 C 语言实现非比较排序(计数排序、桶排序和基数排序)

目录 一、计数排序 二、桶排序 三、基数排序 一、计数排序 算法步骤&#xff1a; 找出待排序数组 arr 中的最小值和最大值&#xff08;分别用 min 和 max 表示&#xff09;。 创建一个长度为 max - min 1、元素初始值全为 0 的计数器数组 count。 扫描一遍原始数组&…

2023 年嵌入式世界的3 大趋势分析

目录 大家好&#xff0c;本文讲解了嵌入式发展的3个大趋势&#xff0c;分享给大家。 趋势#1 – Visual Studio Code Integration 趋势#2 –支持“现代”软件流程 趋势 #3 – 在设计中利用 AI 和 ML 结论 大家好&#xff0c;本文讲解了嵌入式发展的3个大趋势&#xff0c;分享…

Python圈的普罗米修斯——一套近乎完善的监控系统

文章目录前言一、怎么采集监控数据&#xff1f;二、采集的数据结构与指标类型2.1 数据结构2.2 指标类型2.3 实例概念2.4.数据可视化2.5.应用前景总结前言 普罗米修斯(Prometheus)是一个SoundCloud公司开源的监控系统。当年&#xff0c;由于SoundCloud公司生产了太多的服务&…