栈(Stack)and leetcode刷题

news2024/12/29 11:43:05

栈(Stack)and leetcode刷题

  • 1. 栈(Stack)的概念
  • 2. 栈(Stack)的实现
    • 2.1 用数组实现
    • 2.2 用链表实现
      • 2.2.1 用单链表实现
  • 3. leetcode刷题
    • 3.1 括号匹配问题
    • 3.2 栈的弹出压入序列
    • 3.3 逆波兰表达式求值
      • 中缀表达式和后缀表达式
    • 3.4 最小栈
  • 4. 栈、虚拟机栈、栈帧有什么区别?

1. 栈(Stack)的概念

栈是一种线性表,它的结构可以类比于无盖容器,元素遵循“先进后出”的原则

例如:将12,23,34,45,56依次放入栈中,如图:
在这里插入图片描述

当需要取出栈中的元素中,需要依次取出最上面的元素,不能直接取出下面的元素。所以,该栈取出元素的顺序只能为:56,45,34,23,12

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

值得注意的是:压栈的过程中也可以进行出栈,即压栈和出栈可以交替进行

2. 栈(Stack)的实现

栈(Stack)既可以使用数组来实现,也可以使用链表来实现

2.1 用数组实现

用数组来实现栈需要创建三个文件:MyStack.java、EmptyStackException.java、Test.java。下面仅展示MyStack.java和EmptyStackException.java文件,Test.java测试文件不做展示

MyStack.java:

public class MyStack {
    public int[] elem;
    public int usedSize;

    public MyStack() {
        this.elem = new int[10];
    }

    //入栈
    public void push(int val) {
        if(isFull()) {
            //扩容
            elem = Arrays.copyOf(elem, 2*elem.length);
        }
        elem[usedSize++] = val;
    }

    public boolean isFull() {
        return usedSize == elem.length;
    }

    //出栈,会删除栈顶元素
    public int pop() {
        if(isEmpty()) {
            throw new EmptyStackException();
        }
        int val = elem[usedSize-1];
        usedSize--;
        return val;
    }
    //获取栈顶元素 但是不删除
    public int peek() {
        if(isEmpty()) {
            throw new EmptyStackException();
        }
        return elem[usedSize-1];
    }

    public boolean isEmpty() {
        return usedSize == 0;
    }
}

EmptyStackException.java:

public class EmptyStackException extends RuntimeException{
    public EmptyStackException() {
    }

    public EmptyStackException(String message) {
        super(message);
    }
}

其中,EmptyStackException.java是自定义异常,用于抛出空栈异常。

2.2 用链表实现

链表分为单链表和双链表,用哪个来实现好呢?其实两个都是可以的!

2.2.1 用单链表实现

假如用单链表实现时,当压栈(或者出栈)时,用采用头插(头删)还是尾插(尾删)呢?

  • 若采用尾插和尾删,则每次都需要找到尾节点,就算用一个引用last标志尾节点,当尾删尾节点后,需要重新遍历链表找到尾节点,进而重新用last引用标记尾节点,这时的时间复杂度就是O(N)。
  • 若采用头插和头删,每次只需将头节点head向前或向后移动就可以了,时间复杂度为O(1)。

综上可知,当采用单链表实现栈时,采用头插和头删更好!

3. leetcode刷题

3.1 括号匹配问题

题目链接:有效的括号

解题思路:

  1. 遍历字符串,如果是左括号,放入栈中;如果是右括号,就与栈顶的元素比较看是否相同
  2. 如果相同,则将栈顶元素弹出;不同则返回false
  3. 再考虑左右括号数不相等的情况

代码如下:

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 {
                if(stack.isEmpty()) {
                    //左括号数少于右括号数的情况
                    return false;
                }
                char ch2 = stack.peek();
                if((ch2 == '(' && ch == ')') 
                || (ch2 == '[' && ch == ']') 
                || (ch2 == '{' && ch == '}')) {
                    stack.pop();
                } else {
                    return false;
                }
            }
        }
        if(!stack.isEmpty()){
            //左括号数多于右括号数的情况
            return false;
        }
        return true;
    }
}

3.2 栈的弹出压入序列

题目链接:JZ31 栈的压入、弹出序列

解题思路:

  1. 分别遍历pushV数组和popV数组,依次将pushV数组中元素放入栈中,每次放入一个元素到栈中的同时,比较栈顶元素是否与数组popV当前元素是否相等,相等则弹出栈顶元素
  2. 由于栈顶元素弹出后,新的栈顶元素可能与数组popV的下一个相等,因此需要循环比较
  3. 当栈为空,且popV数组遍历完时,popV数组为pushV数组的一个弹出顺序

代码如下:

public boolean IsPopOrder (int[] pushV, int[] popV) {
        // write code here
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for(int i = 0; i < pushV.length; i++) {
            stack.push(pushV[i]);
            //注意循环的条件
            while(!stack.isEmpty() && j < popV.length && stack.peek() == popV[j]) {
                stack.pop();
                j++;
            }
        }
        if(stack.isEmpty() && j == popV.length) {
            return true;
        }
        return false;
    }

3.3 逆波兰表达式求值

中缀表达式和后缀表达式

在做这道题之前,我们需要了解什么是逆波兰表达式。逆波兰表达式又叫做后缀表达式,而我们平常所见到的表达式是一般都是中缀表达式,下面通过一个例子来讲解如何由中缀表达式得到后缀表达式

例: 中缀表达式a + bc+(de+f)g,其转换成后缀表达式则为abc+def+g+,演算过程如下图:
在这里插入图片描述
假如例子中a,b,c,d,e,f,g分别取1,2,3,4,5,6,7。由中缀表达式可以很容易求得该表达式的结果为189,那么怎么由后缀表达式求值呢?运用后缀表达式求值需要用到栈

后缀表达式求值规则: 从左往后,如果是数字,就将其放去栈中;如果是加减乘除符号,取出一个栈顶元素作为该符号的右操作数,再取出一个栈顶元素做为左操作数,计算得到的结果放入栈中,如此下去,最后栈中只会剩一个元素,这就是最终的结果
在这里插入图片描述

题目链接:150. 逆波兰表达式求值

解题思路:

  1. 遍历字符串数组,判断是数字还是符号
  2. 如果是数字,则将该数字转化为整型后,放入栈中
  3. 如果是符号,取出栈顶元素作为右操作数,再取出一个栈顶元素作为左操作数,进行运算,得到的运算结果放入栈中
  4. 最终栈中的元素即为后缀表达式的运算结果

代码如下:

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < tokens.length; i++) {
            //判断是否为符号
            if(tokens[i].equals("+") 
            || tokens[i].equals("-") 
            || tokens[i].equals("*") 
            || tokens[i].equals("/")) {
                int val2 = stack.pop();
                int val1 = stack.pop();
                int result = 0;
                //进行运算操作
                switch(tokens[i]) {
                    case "+":
                        result = val1+val2;
                        break;
                    case "-":
                        result = val1-val2;
                        break;
                    case "*":
                        result = val1*val2;
                        break;
                    case "/":
                        result = val1/val2;
                        break;
                }
                //将运算结果放入栈中
                stack.push(result);
                continue;
            }
            int val = Integer.parseInt(tokens[i]);
            stack.push(val);
        }
        return stack.pop();
    }
}

计算机的工作原理也是这样的,将你输入的中缀表达式转化为后缀表达式,再按照后缀表达式的运算规则进行运算,得到结果!

3.4 最小栈

题目链接:155. 最小栈

解题思路:

  1. 这道题想表达的意思是得到当前栈中的最小元素,而这个栈是可以压栈或出栈的,因此这个最小元素也是变化的
  2. 想解决这道题,仅仅靠一个栈是不够的。需要创建两个栈,一个普通栈stack,一个最小栈minStack

入栈:

  1. 普通栈是一定要放的,最小栈放的原则:1. 如果普通栈为空,则最小栈也要放;2.如果入栈元素小于最小栈的栈顶元素,则需要放
  2. 这时就有一个问题了:如果入栈元素等于最小栈的栈顶元素,那么需要放吗?答案是需要的!因为当出栈时,普通栈的这个元素(即最小元素)出去时,最小栈的栈顶元素也同样需要出去。如果入栈的时候不放,那么在出栈后,得到的最小元素就可能不对了!举个例子:假设普通栈里有0,1,-1,-2,2,-2,那么对应最小栈里有0,-1,-2,-2,假如普通栈最后一个元素入栈时没有放入最小栈,那么最小栈里就只有0,-1,-2,而当后面出栈时,普通栈出去了-2,最小栈的栈顶元素也是-2,同样也需要出栈。出栈后最小栈里就只有0,-1了,就说明此时普通栈的最小元素为-1,而事实上普通栈的最小元素为-2,这互相矛盾了。因此当入栈元素等于最小栈的栈顶元素,需要放入最小栈

出栈:

  1. 需要判断普通栈的出栈元素是否与最小栈的栈顶元素相等,相等则最小栈也需要出栈

代码如下:

class MinStack {
    public Stack<Integer> stack;
    public  Stack<Integer> minStack;
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.empty()) {
            minStack.push(val);
        }else {
            int peekVal = minStack.peek();
            if(val <= peekVal) {
                minStack.push(val);
            }
        }
    }
    public void pop() {
        if(stack.empty()) {
            return;
        }
        int popVal = stack.pop();
        if(popVal == 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();
    }
}

4. 栈、虚拟机栈、栈帧有什么区别?

栈是一种数据结构;虚拟机栈是JVM中的一块内存;当你运行一个方法,给这个方法开辟的内存叫做栈帧

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cartographer重入门到精通(二):运行作者demo及自己的数据集

在demo数据包上运行cartographer 现在Cartographer和Cartographer的Ros包已经都安装好了&#xff0c;你可以下载官方的数据集到指定的目录&#xff08;比如在Deutsches Museum用背包采集的2D和3D 数据&#xff09;&#xff0c;然后使用roslauch来启动demo。 注&#xff1a;la…

一文了解5G新通话技术演进与业务模型

5G新通话简介 5G新通话&#xff0c;也被称为VoNR&#xff0c;是基于R16及后续协议产生的一种增强型语音通话业务。 它在IMS网络里新增数据通道&#xff08;Data Channel&#xff09;&#xff0c;承载通话时的文本、图片、涂鸦、菜单等信息。它能在传统话音业务基础上提供更多服…

拓扑排序——AcWing 164. 可达性统计

目录 拓扑排序 定义 运用情况 注意事项 解题思路 AcWing 164. 可达性统计 题目描述 运行代码 代码思路 改进思路 拓扑排序 定义 拓扑排序&#xff08;Topological Sort&#xff09;是对有向无环图&#xff08;Directed Acyclic Graph&#xff0c;简称DAG&#xff…

【论文阅读笔记】ASPS: Augmented Segment Anything Model for Polyp Segmentation

1.论文介绍 ASPS: Augmented Segment Anything Model for Polyp Segmentation ASPS&#xff1a;用于息肉分割的扩展SAM模型 2024年 arxiv Paper Code 2.摘要 息肉分割在结直肠癌诊断中起着至关重要的作用。最近&#xff0c;Segment Anything Model(SAM)的出现利用其在大规模…

去水印小程序源码修复版-前端后端内置接口+第三方接口

去水印小程序源码&#xff0c;前端后端&#xff0c;内置接口第三方接口&#xff0c; 修复数据库账号密码错误问题&#xff0c;内置接口支持替换第三方接口&#xff0c; 文件挺全的&#xff0c;可以添加流量主代码&#xff0c;搭建需要准备一台服务器&#xff0c;备案域名和http…

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…

交换机和路由器的工作流程

1、交换机工作流程&#xff1a; 将接口中的电流识别为二进制&#xff0c;并转换成数据帧&#xff0c;交换机会记录学习该数据帧的源MAC地址&#xff0c;并将其端口关联起来记录在MAC地址表中。然后查看MAC地址表来查找目标MAC地址&#xff0c;会有一下一些情况&#xff1a; MA…

java.sql.SQLException: Before start of result set

情况描述&#xff0c;在通过JDBC连接数据库时&#xff0c;想直接判断获取的值是否存在&#xff0c;运行时报错。 翻译&#xff1a; 在开始结果集之前 报错截图 解决问题的方法&#xff1a;对结果集ResultSet进行操作之前&#xff0c;一定要先用ResultSet.next()将指针移动至…

4K60无缝一体矩阵 HDMI2.0功能介绍

关于GF-HDMI0808S 4K60无缝一体矩阵的功能介绍&#xff0c;由于直接针对GF-HDMI0808S型号的具体信息较少&#xff0c;我将结合类似4K60无缝HDMI矩阵的一般功能特性和可能的GF-HDMI0808系列产品的特点来进行说明。请注意&#xff0c;以下信息可能不完全针对GF-HDMI0808S型号&…

vienna整流器的矢量分析

Vienna整流器使用六个二极管和六个IGBT&#xff08;或MOSFET&#xff09;组成&#xff0c;提供三个电平&#xff1a;正极电平&#xff08;P&#xff09;、中性点电平&#xff08;O&#xff09;和负极电平&#xff08;N&#xff09;。通过对功率管的控制&#xff0c;Vienna整流器…

xmind梳理测试点,根据这些测试点去写测试用例

基本流&#xff08;冒烟用例必写&#xff09; 备选流 公共测试点&#xff1a;

算法笔记——LCR

一.LCR 152. 验证二叉搜索树的后序遍历序列 题目描述&#xff1a; 给你一个二叉搜索树的后续遍历序列&#xff0c;让你判断该序列是否合法。 解题思路&#xff1a; 根据二叉搜索树的特性&#xff0c;二叉树搜索的每一个结点&#xff0c;大于左子树&#xff0c;小于右子树。…

【企业级监控】Zabbix实现邮箱报警

Zabbix监控自动化 文章目录 Zabbix监控自动化资源列表基础环境前言四、Zabbix邮件告警4.1、实现报警所需的条件4.1.1、告警媒介4.1.2、触发器&#xff08;trigger&#xff09;4.1.3、动作&#xff08;action&#xff09; 4.2、配置告警媒介4.2.1、设置告警媒介参数4.2.2、启用此…

SpringCloud教程 | 第八篇: 使用seata处理分布式事务

1、参考程序员江小北 2、打算降低nacos版本&#xff0c;先学通再看看升级到高版本nacos能不能正常使用。 3、nacos用1.4.1&#xff0c;正常启动单机版的了 4、seata用2.0.0 我看江小北说用的1.4.0的seata&#xff0c;但是图片中的目录文件都找不到&#xff0c;倒是在2.0.0的…

弥合人类与人工智能的知识差距:AlphaZero 中的概念发现和迁移(1)

文章目录 一、摘要二、简介三、相关工作3.1 基于概念的解释3.2 强化学习中生成解释3.3 国际象棋与人工智能 四、什么是概念&#xff1f;五、发掘概念5.1 挖掘概念向量5.1.1 静态概念的概念约束5.1.2 动态概念的概念约束 5.2 过滤概念 一、摘要 人工智能&#xff08;AI&#xff…

计算机网络--tcpdump和iptable设置、内核参数优化策略

tcpdump工具 tcpdump命令&#xff1a; 选项字段&#xff1a; 过滤表达式&#xff1a; 实用命令&#xff1a; TCP三次握手抓包命令&#xff1a; #客户端执行tcpdump 抓取数据包 tcpdump -i etho tcp and host 192.168.12.36 and port 80 -W timeout.pcapnetstat命令 netst…

昇思25天学习打卡营第12天 | ResNet50图像分类

昇思25天学习打卡营第12天 | ResNet50图像分类 文章目录 昇思25天学习打卡营第12天 | ResNet50图像分类ResNet网络模型残差网络结构Building BlockBottleneck 训练数据准备训练数据可视化 网络构建Build Block结构Bottleneck结构ResNet50网络 模型训练与评估训练验证迭代数据集…

Swiftui中几种常用的数据存储方式@AppStorage/UserDefaults/CoreData/File Storage/Keychain等

在 SwiftUI 中&#xff0c;有多种常用的数据存储方式&#xff0c;根据需求的不同&#xff0c;可以选择适合的存储方案。以下是几种常用的数据存储方式&#xff1a; AppStorage/UserDefaults/CoreData/File Storage/Keychain&#xff0c;分别来看一下他们的使用场景和区别。 1.…

【Linux 文件读写描述符重定向 Linux 一切皆文件缓冲区】

文章目录 一、文件的读写操作二、文件描述符三、文件重定向四、理解 Linux 一切皆文件五、文件缓冲区 一、文件的读写操作 文件内容属性 当文件没有被操作的时候&#xff0c;一般文件还是在磁盘当中 文件操作文件内容的操作文件属性的操作&#xff0c;文件操作有可能即改变内容…

实战:docker式部署frp内网穿透-2024.7.13(测试成功)

前提 首先就需要准备好一台云服务器&#xff0c;用于提供公网 IP 和流量转发。至于购买哪家的云服务产品&#xff0c;本着能省则省的原则&#xff0c;这个当然是哪家便宜用哪家呢。 我手上目前有闲置的腾讯云的服务器&#xff0c;刚好可以用来作为内网穿透的机器&#xff0c;…