227. 基本计算器 II
- 原题链接:
- 完成情况:
- 解题思路:
- 参考代码:
- _227基本计算器II_单栈直接算
- _227基本计算器II_双栈
- 错误经验吸取
原题链接:
227. 基本计算器 II
https://leetcode.cn/problems/basic-calculator-ii/
完成情况:
解题思路:
这段代码是一个用于计算表达式的类。它使用两个栈opers
和nums
来存储运算符和操作数。在calculate
函数中,它遍历输入的字符串表达式s
,根据不同的情况进行处理。具体来说:
- 如果遇到空格,则跳过。
- 如果遇到左括号
(
,将其压入opers
栈中,并检查下一个字符是否为负号-
,若是,则将0压入nums
栈中,并将负号-
压入opers
栈中。 - 如果遇到右括号
)
,则不断计算直到遇到左括号(
。 - 如果遇到数字字符,则将连续的数字字符转换为整数,并压入
nums
栈中。 - 如果遇到运算符,则与栈顶运算符比较优先级,若当前运算符优先级小于等于栈顶运算符,则进行计算,直到栈顶运算符优先级小于当前运算符,然后将当前运算符压入
opers
栈中。 - 最后,当遍历完整个表达式后,不断计算直到
opers
栈为空,并返回nums
栈顶元素作为最终计算结果。
cal
函数用于实际计算操作数和运算符的结果,并将结果压入nums
栈中。
这段代码实现了一个简单的表达式计算器,支持加减乘除取模和幂运算。
参考代码:
_227基本计算器II_单栈直接算
package leetcode板块;import java.util.ArrayDeque;
import java.util.Deque;public class _227基本计算器II_单栈直接算 {/*** String类型实现双栈* @param s* @return*/public int calculate(String s) {//双栈实现,一个栈存储数字,一个栈存储计算式//然后就是数字栈还需要往后看一个,因为如果是连续的数字,那么说明其实他们同属于一个数值Deque<Integer> myStack = new ArrayDeque<Integer>();char preSign = '+';int num = 0;int n = s.length();for(int i = 0;i<n;++i){if (Character.isDigit(s.charAt(i))){num = num*10 + s.charAt(i) - '0';}if (!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' '|| i == n-1){switch (preSign){case '+':myStack.push(num);break;case '-':myStack.push(-num);break;case '*':myStack.push(myStack.pop() * num);break;case '/':myStack.push(myStack.pop() / num);break;}preSign = s.charAt(i);num = 0;}}int res = 0;while (!myStack.isEmpty()){res += myStack.pop();}return res;}
}
_227基本计算器II_双栈
package leetcode板块;import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;public class _227基本计算器II_双栈 {//这里的优先级划分按照「数学」进行划分即可Map<Character,Integer> map = new HashMap<>(){{put('-',1);put('+',1);put('*',2);put('/',2);put('%',2);put('^',3);}};/**** @param s* @return*/public int calculate(String s){/*实例:输入:s = " 3+5 / 2 "输出:5*///先去除掉所有的空格s = s.replaceAll(" ","");//将字符串转化成字符数组char [] chars = s.toCharArray();int n = s.length();//构建数字栈Deque<Integer> nums = new ArrayDeque<Integer>();//构建操作符栈Deque<Character> options = new ArrayDeque<>();//为了防止第一个数是负数,且我们没有在一开始就考虑正负号的问题,所以在最外层//所以一开始先加一个0nums.addLast(0);for (int i = 0;i<n;i++){char ch = chars[i];if (ch == '('){ //遇到左括号,必定最高优先添加options.add(ch);}else if (ch == ')'){ //遇到右括号,那么就赶紧把栈里面都计算掉while (!options.isEmpty()){if (options.peekLast() != '('){calcNumsAndOptions(nums,options);}else {options.pollLast();break;}}}else {if (isNumber(ch)){int u = 0;int j = i;//判断是否会有连续数字while (j < n && isNumber(chars[j])){u = u*10 + (chars[j++] - '0');}nums.addLast(u);i = j - 1;}else {if (i>0 && (chars[i-1] == '(' || chars[i-1] == '+' || chars[i-1] == '-')){nums.addLast(0);}// 有一个新操作要入栈时,先把栈内可以算的都算了// 只有满足「栈内运算符」比「当前运算符」优先级高/同等,才进行运算while (!options.isEmpty() && options.peekLast() != '('){char prev = options.peekLast();if (map.get(prev) >= map.get(ch)){calcNumsAndOptions(nums,options);}else {break;}}options.addLast(ch);}}}//将剩余的计算完while (!options.isEmpty()){calcNumsAndOptions(nums,options);}return nums.peekLast();}/**** @param ch* @return*/private boolean isNumber(char ch) {return Character.isDigit(ch);}/**** @param nums* @param options*/private void calcNumsAndOptions(Deque<Integer> nums, Deque<Character> options) {if (nums.isEmpty() || nums.size() < 2) return;if (options.isEmpty()) return;int b = nums.pollLast(),a = nums.pollLast();char ops = options.pollLast();int res = 0;if (ops == '+'){res = a+b;}else if (ops == '-'){res = a-b;}else if (ops == '*'){res = a*b;}else if (ops == '/'){res = a/b;}else if (ops == '^'){res = (int)Math.pow(a,b);}else if (ops == '%'){res = a%b;}nums.addLast(res);}
}