Java LeetCode篇-深入了解关于栈的经典解法(栈实现:中缀表达式转后缀)

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
   

文章目录

        1.0 中缀表达式转后缀说明

        1.1 实现中缀表达式转后缀思路

        2.0 逆波兰表达式求值

        2.1 实现逆波兰表达式求值思路

        3.0 有效的括号

        3.1 实现有效的括号思路

        4.0 栈的压入、弹出序列

        4.1 实现栈的压入、弹出序列思路

        5.0 最小栈

        5.1 实现最小栈思路


        1.0 中缀表达式转后缀说明

        中缀表达式转后缀表达式是一种常见的算术表达式转换方法,它将中缀表达式(即常见的人类习惯的表达方式,例如("3 + 4 * 2")转换为后缀表达式(也称为逆波兰表达式,例如 " 3 4 2 * +")。中缀表达式转后缀表达式的转换过程通常使用栈来实现

        1.1 实现中缀表达式转后缀思路

        1.1.1 思路具体为:首先先来讨论优先级问题,分两种情况。

        情况一:不带括号,对于 " + " " - " " * " " / ",这个四种运算符来定义优先级大小,"+" "-" 优先级大小可以设置为 1," * " " / " 优先级大小可以设置为 2 。

        情况二:带括号,对于 " ( "  来说,将其优先级设置为 0 ,为最小的优先级。

        再来讨论代码实现的流程:对于运算符或者括号来说,将其放到栈中暂时存储;对于数字 0 ~ 9 来说,将其拼接到可变字符串中。

        1.1.2 接下来循环遍历字符串

        (1) 遇到非运算符,直接拼串

        (2) 遇到 + - * /

                - 它的优先级比栈顶运算符高,入栈,如:栈中是 + ,当前是 * 

                - 否则把栈里面的优先级 >= 它的都出栈,它再进栈,如栈中是 +* ,当前是 -

        (3) 遍历完成,栈里面剩余运算符依次出栈拼接到字符串中

        (4) 带()

                - 遇到左括号直接入栈,左括号优先级设置为 0 。

                - 遇到右括号就把栈里面到左括号为止的所有运算符都出栈

代码如下:

import java.util.Stack;public class TurnToSuffix {public static void main(String[] args) {String s = "(a+b)*c";System.out.println(turnSuffix(s));String s1 = "(a+b*c-d)*e";System.out.println(turnSuffix(s1));String s2 = "a*(b+c)";System.out.println(turnSuffix(s2));}public static String turnSuffix(String s) {if (s.length() == 0) {return null;}StringBuilder str = new StringBuilder();Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);switch (ch) {case '(' -> {//如果是有括号,直接进栈stack.push(ch);}case '+', '-','*','/' -> {//比较优先级,进栈的优先级高,不需要弹出;进栈的优先级底或者同一级别,需要弹出。while ( !stack.isEmpty() && priority(ch) <= priority(stack.peek())) {str.append(stack.pop());}stack.push(ch);}case ')' -> {while ( !stack.isEmpty() && stack.peek() != '(') {str.append(stack.pop());}stack.pop();}default -> {str.append(ch);}}}int num = stack.size();for (int j = 0; j < num; j++) {str.append(stack.pop());}return str.toString();}public static int priority(char f) {if (f == '(') {return 0;} else if (f == '+' || f == '-') {return 1;}else if (f == '*' || f == '/' ) {return 2;}return -1;}
}

        2.0 逆波兰表达式求值

         逆波兰表达式(也称为后缀表达式)是一种不需要括号来表示运算顺序的算术表达式。它的计算方式是从左到右扫描表达式,遇到操作数就将其压入栈中,遇到操作符就从栈中弹出相应数量的操作数进行运算,并将结果再次压入栈中。最终栈中的唯一元素就是表达式的值。

题目:

        给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

        2.1 实现逆波兰表达式求值思路

        思路具体为:遍历字符串数组,将遍历遇到的非运算符都要存放在栈中;遇到运算符需要将栈中的数据弹出栈,第一个弹出的数据称为右操作数,第二个弹出来的数据称为左操作数。接着对应相应的运算符进行对该这两个数据操作,得到的计算结果需要重新压入栈中。最后循环结束,栈中存放的就是该表达式最终的结果了。

代码如下:

class Solution {public static int evalRPN(String[] tokens) {LinkedList<Integer> stack = new LinkedList<>();for (int i = 0; i < tokens.length; i++) {int a = 0;int b = 0;switch (tokens[i]) {case "+":b = stack.pop();a = stack.pop();stack.push(a + b);break;case "-":b = stack.pop();a = stack.pop();stack.push(a - b);break;case "*":b = stack.pop();a = stack.pop();stack.push(a * b);break;case "/":b = stack.pop();a = stack.pop();stack.push(a / b);break;default:stack.push(Integer.parseInt(tokens[i]));break;}}return stack.pop();}
}

        需要注意的点是:从字符串数组中得到的非运算符是,需要将其转换为 int 的包装类型。

        3.0 有效的括号

题目:

        给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

该题的 LeetCode 链接:20. 有效的括号

        3.1 实现有效的括号思路

        具体思路为:遍历字符串,每一次循环得到的字符可以大致分为两种情况:

        第一种情况:遇到的是右括号,无论是 ' ( '  ' { '  ' [ '  的其中一种,都需要将其相反的符号压入栈中。如:遇到的是 ' ( ' ,那么需要压入栈的是 ' ) '

        第二种情况:遇到的是左括号,无论是  ' ) '  ' } '  ' ] '  的其中一种,先要判断栈中是否为空,如果为空,直接返回 false ;当不为空时,若判断栈顶的括号是否跟遇到的左括号相等,如果相等,将栈顶的括号弹出,若不相等,直接返回 false

        最后循环结束了,判断栈是否为空,如果栈为空了,那么说明都一一对称,有相应的括号与之匹配;如果不为空,那么说明,不是全部的括号都要相应的括号对应。

代码如下:

class Solution {
public  static boolean isValid(String s) {if (s.length() == 0) {return false;}Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);switch (ch) {case '[' -> {stack.push(']');}case '{' -> {stack.push('}');}case '(' -> {stack.push(')');}default -> {if (stack.empty()) {return false;}if (ch != stack.peek()) {return false;} else if (ch == stack.peek()) {stack.pop();}}}}return stack.empty();}
}

        4.0 栈的压入、弹出序列

题目:

        输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

1. 0<=pushV.length == popV.length <=1000

2. -1000<=pushV[i]<=1000

3. pushV 的所有数字均不相同

示例1

输入:

[1,2,3,4,5],[4,5,3,2,1]

返回值:

true

说明:

可以通过push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=>pop()=>pop()
这样的顺序得到[4,5,3,2,1]这个序列,返回true      

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

        4.1 实现栈的压入、弹出序列思路

        第一个序列表示栈的压入顺序第二个序列可能为该栈的弹出顺序

        具体思路为:遍历第一个序列,每一次得到的数值都要跟第二个序列索引从 0 开始到该序列长度 - 1 比较,如果从第一个序列得到的数值跟第二个序列的数值不相同时,需要将第一序列的数值压入栈中;如果从第二个序列得到的数值跟第二个序列的数值相同时,需要将第一个序列的数值弹出栈中,接着第二个序列跳到下一个数值跟栈中的数值进行比较,若相同,栈中继续弹出,第二个序列继续跳到下一个。若不相同,继续遍历第一个序列。

        可以简单的理解为:每一次循环第一个序列得到数据都要放到栈中,接着跟第二个序列的数据进行比较。如果栈顶的数据跟第二个序列的数值相同时,需要将其栈顶元素弹出,还需要将第二个序列移到下一个元素。接着继续比较,直到栈顶元素跟第二个序列的元素不相等是,继续遍历第一个序列,直到第一个序列遍历完毕。最后判断占是否为空,若为空,返回 true ;若不为空,返回 false 。

代码如下:

import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型一维数组 * @param popV int整型一维数组 * @return bool布尔型*/public boolean IsPopOrder (int[] pushV, int[] popV) {// write code hereStack<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++;}}return stack.isEmpty();}
}

        需要注意的是,在内层循环时,要保证栈中不为空且不能超过第二个序列的长度。

      

        5.0 最小栈

题目:

        设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]输出:
[null,null,null,null,-3,null,0,-2]解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

该题的 LeetCode 链接为:155. 最小栈

        5.1 实现最小栈思路

        具体思路为:因为需要记录栈中的最小元素,所以需要用到两个栈,对于 stack 栈来说,就正常的压栈、出栈、查看栈顶元素等操作即可;

        压栈处理:对于 minStack 栈来说,当该栈为空时,stack 压栈时minStack 也要压栈相同的元素;当 minStack 不为空时,satck 压栈时,minStack 需要先判断该栈顶元素的值是否大于需要压入栈的元素的值,若大于等于,则 minStzck 需要将其压入栈,若小于,则不需要进行任何操作。

        出栈处理:需要先判断 stack 是否为空栈,如果是空栈,则不需要进行出栈处理。如果不为空栈,stack 需要出栈,但是对于 nimStack 不一定需要出栈,若 stack 的栈顶与 nimStack 的栈顶元素相同时,nimStack 需要出栈。若不相同,则不需要出栈。

        查看栈顶元素处理:直接返回 stack.pop() 即可。

        查看最小栈的元素:直接返回 minStack.peek() 即可。

代码如下:

class MinStack {Stack<Integer> stack;Stack<Integer> minStack ;public MinStack() {stack  = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if(minStack.isEmpty()) {minStack.push(val);}else if(minStack.peek() >= val) {minStack.push(val);}}public void pop() {if(stack.pop().equals(minStack.peek())){minStack.pop();}}public int top() {return stack.peek();}public int getMin() {return minStack.peek();}
}

        需要注意的是, stack minStack 的栈顶元素进行比较时,需要用 equals() 方法进行比较,不然会发生问题。

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

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

相关文章

法学毕业生个人简历16篇

想要从众多法学毕业求职者中脱颖而出&#xff0c;找到心仪的相关工作&#xff1f;可以参考这16篇精选的法学专业应聘简历案例&#xff0c;无论是应届比预算还是有工作经验&#xff0c;都能从中汲取灵感&#xff0c;提升简历质量。希望对大家有所帮助。 法学毕业生简历模板下载…

RPG项目01_脚本代码

基于“RPG项目01_场景及人物动画管理器”&#xff0c;我们创建一个XML文档 在资源文件夹下创建一个文件夹&#xff0c; 命名为Xml 将Xnl文档拖拽至文件夹中&#xff0c; 再在文件夹的Manager下新建脚本LoadManager 写代码&#xff1a; using System.Collections; using System…

Pycharm调用Conda虚拟环境

参考这个链接的评论区回答&#xff1a;Pycharm调用Conda虚拟环境 笑死&#xff0c;我之前也是这样的&#xff0c;不过好像也能用&#xff0c;搞不懂~

Ontrack EasyRecovery2024数据恢复软件详细功能介绍

Ontrack EasyRecovery2024是一款功能强大的数据恢复软件&#xff0c;它可以帮助用户从各种存储设备中恢复丢失或删除的数据。它支持多种文件系统和文件类型&#xff0c;可以恢复包括照片、视频、音频、文档、电子邮件和归档文件等不同类型的数据。 EasyRecovery15Mac版本下载如…

文案二次创作软件,文案二次创作的软件

文案创作成为品牌传播和营销不可或缺的一环。对于许多从业者而言&#xff0c;文案创作常常是一项既耗时又耗力的工作。为了解决这一文案创作的难题&#xff0c;市场上涌现出了众多的智能文案生成工具。我们通过对这些工具的介绍和分析&#xff0c;希望能够为你提供一些在文案创…

Micropython for QNX编译过程

Micropython for QNX编译过程 执行步骤 1. https://github.com/micropython/micropython select tag 1.20.0 git clone micropython 2. make -C mpy-cross 3. 修改py/mkenv.mk CROSS_COMPILE ntoaarch64- 注意如果这步必须在make -C mpy-cross 之后执行&#xff0c;如果需要重…

宝塔+docker+jenkins部署vue项目----笔记版

宝塔dockerjenkins部署vue项目&#xff08;保姆级教程&#xff09;https://blog.csdn.net/weixin_47284756/article/details/129339940 基于上述教程&#xff0c;不同的地方。 1.我使用的是gitee&#xff0c;所以需要在jenkins中安装gitee插件 配置gitee&#xff0c;其他默认配…

SmartsoftHelp8,条形码,二维码 生成,解析 专业工具

生成条形码 生成二维码 条形码解析 二维码解析 专业工具 下载地址&#xff1a; https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

大学程序员的养生之道

呀哈喽&#xff0c;我是结衣。 今天给大家带来的是大学程序员的养生之道&#xff01; 作为一名大学生还没有深刻的感受到未来的恐怖&#xff0c;但每当我看到这些对程序员的评价还是不禁感慨。 不要让自己的学习之路变成这样啊&#xff01;程序员的职业发展&#xff1a;某编程语…

CSS:calc() 函数 / 动态计算长度值 / 不同场景使用

一、理解 css calc() 函数 CSS calc() 函数是一个用于计算 CSS 属性值的函数。它可以在 CSS 属性值中使用数学表达式&#xff0c;从而实现动态计算属性值的效果。calc() 函数可以使用加减乘除四种基本数学运算符来计算属性值&#xff0c;还可以使用括号来改变优先级。 二、ca…

【brew】Mac上安装vue3

先安装node。 这里我从其他博客找的方案&#xff0c;原始脚本下载太慢了。 cnpm的安装&#xff1a; 让npm更快一点。 npm install -g cnpm --registryhttps://registry.npm.taobao.org安装vue脚手架 2.0版本&#xff1a;sudo npm install -g vue-cli 3.0版本&#xff1a; sud…

Java实战案例————ATM

需求分析 首先ATM银行系统包括两个基础大功能&#xff1a;开户和登陆账户&#xff08;当然在系统中没有一个账户时不能登录&#xff0c;需要先开户&#xff09;。 一名用户有6项基本信息描述&#xff1a;姓名、性别、银行卡号、银行卡密码、账户余额、取款限额。 在登录账户…

QNX常用调试方法

QNX常用调试方法 1. top 查询系统状态最常用的工具是top&#xff0c;它可以显示系统资源的使用情况。我们最关心的通常是系统可用内存和CPU使用率。如果CPU使用率过高可能是因为某些应用存在bug&#xff0c;重点关注下面显示的占用CPU资源最多的几个线程。如果可用内存太少&am…

Fisher信息理论与应用

一、概念介绍 Fisher信息量&#xff0c;是一次观测值所能提供的关于未知参数θ的信息量期望值的一种度量。 Fisher信息矩阵&#xff0c;是用利用最大似然函数估计来计算方差矩阵&#xff0c;表示随机变量的一个样本所能提供的关于状态参数在某种意义下的平均信息量。 Fisher…

node.js express路由和中间件

目录 路由 解释 使用方式 中间件 解释 使用方式 中间件类型 路由注册和中间件注册 代码 app全局路由接口请求以及代码解析 示例1 示例2 示例3 示例4 中间件req继承 嵌套子路由 解释 代码 示例1 路由 解释 在 Express 中&#xff0c;路由&#xff08;Route&…

【Qt开发流程】之事件系统3:键盘事件

序章 以下链接是拖放事件介绍和使用示例&#xff1a; 【Qt开发流程】之拖放操作1:介绍链接: https://blog.csdn.net/MrHHHHHH/article/details/134626484 【Qt开发流程】之拖放操作2:使用链接: https://blog.csdn.net/MrHHHHHH/article/details/134632006 以下链接是事件系统…

百度智能云推出“千帆AI原生应用开发工作台” 助力开发者创新

在这个智能互联的世界&#xff0c;每一次技术的飞跃都预示着无限可能。你是否曾梦想&#xff0c;一款产品能够打破创新的边界&#xff0c;让开发不再是高门槛的技术挑战&#xff1f;12月20日&#xff0c;百度云智大会智算大会将为你揭开这幕神秘面纱——“千帆AI原生应用开发工…

orvibo旗下的VS30ZW网关分析之一

概述 从官网的APP支持的智能中枢来看,一共就两种大类: MixPad系列和网关系列 排除MixPad带屏网关外,剩余的设备如下图: 目前在市场上这四种网关已经下市,官方已经宣布停产。所以市场上流通的也几乎绝迹。 从闲鱼市场上可以淘到几个,拿来分析一下,这里我手头有如下的两…

配置typroa上传图片到gitee

在typora这个位置下载插件 在picgo.exe文件夹下输入cmd 打开命令行输入如下命令安装相关插件 .\picgo install gitee-uploader .\picgo install super-prefix 之后按照官方文档更改相关配置 官方文档参考 https://picgo.github.io/PicGo-Core-Doc 博客参考&#xff1a;…

抑郁症中西医治疗对比?

抑郁症是一种常见的心理障碍&#xff0c;治疗方法包括中医和西医两种。下面就抑郁症中西医治疗进行对比&#xff1a; 治疗方法&#xff1a;中医治疗抑郁症强调整体观念和辨证论治&#xff0c;通过调理身体各部分的功能&#xff0c;达到治疗抑郁症的目的。中医治疗抑郁症多采用天…