🔥博客主页: 【小扳_-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:
输入: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() 方法进行比较,不然会发生问题。