基本计算器 III
难度:
标签:
题目描述
代码结果
运行时间: 26 ms, 内存: 16.0 MB
/*
* 基本计算器 III
* 题目思路:
* 1. 使用Java Stream API进行字符串处理。
* 2. 将字符串转换为字符流, 然后进行过滤和映射操作。
* 3. 利用栈数据结构来处理括号和运算符的优先级。
*/
import java.util.*;
import java.util.stream.*;
public class BasicCalculatorIIIStream {
public int calculate(String s) {
Stack<Integer> nums = new Stack<>();
Stack<Character> ops = new Stack<>();
Stream<Character> stream = s.chars().mapToObj(c -> (char) c);
List<Character> list = stream.collect(Collectors.toList());
for (int i = 0; i < list.size(); i++) {
char c = list.get(i);
if (Character.isDigit(c)) {
int num = 0;
while (i < list.size() && Character.isDigit(list.get(i))) {
num = num * 10 + (list.get(i) - '0');
i++;
}
i--;
nums.push(num);
} else if (c == '(') {
ops.push(c);
} else if (c == ')') {
while (ops.peek() != '(') {
nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));
}
ops.pop();
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
while (!ops.isEmpty() && precedence(c) <= precedence(ops.peek())) {
nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));
}
ops.push(c);
}
}
while (!ops.isEmpty()) {
nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));
}
return nums.pop();
}
private int applyOp(char op, int b, int a) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
return 0;
}
private int precedence(char op) {
if (op == '+' || op == '-')
return 1;
if (op == '*' || op == '/')
return 2;
return 0;
}
}
解释
方法:
该题解使用栈来模拟计算过程。从左到右遍历字符串,遇到数字时更新当前数字,遇到左括号时将当前的运算符入栈并重置当前数字和运算符,遇到运算符时根据之前的运算符进行相应的计算并更新当前运算符,遇到右括号时计算括号内的结果并将结果作为数字进行进一步计算。最后将栈中所有数字求和得到最终结果。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在算法中,遇到左括号`(`时,为什么要将当前运算符入栈并重置数字和运算符?这样做的目的是什么?
▷🦆
在处理完括号内的表达式后,为什么需要将括号前的运算符从栈中弹出,并用这个运算符继续计算?
▷🦆
在实现除法时,为什么采用`int(stack.pop() / num)`而不是直接`stack.pop() / num`?这样处理的原因是什么?
▷🦆
该题解在处理运算符时,有考虑运算符的优先级吗?如果有,是如何实现的?如果没有,这样做会有什么潜在问题?
▷相关问题
基本计算器
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval()
。
示例 1:
输入:s = "1 + 1" 输出:2
示例 2:
输入:s = " 2-1 + 2 " 输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)" 输出:23
提示:
1 <= s.length <= 3 * 105
s
由数字、'+'
、'-'
、'('
、')'
、和' '
组成s
表示一个有效的表达式- '+' 不能用作一元运算(例如, "+1" 和
"+(2 + 3)"
无效) - '-' 可以用作一元运算(即 "-1" 和
"-(2 + 3)"
是有效的) - 输入中不存在两个连续的操作符
- 每个数字和运行的计算将适合于一个有符号的 32位 整数
基本计算器 II
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1]
的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval()
。
示例 1:
输入:s = "3+2*2" 输出:7
示例 2:
输入:s = " 3/2 " 输出:1
示例 3:
输入:s = " 3+5 / 2 " 输出:5
提示:
1 <= s.length <= 3 * 105
s
由整数和算符('+', '-', '*', '/')
组成,中间由一些空格隔开s
表示一个 有效表达式- 表达式中的所有整数都是非负整数,且在范围
[0, 231 - 1]
内 - 题目数据保证答案是一个 32-bit 整数
基本计算器 IV
给定一个表达式如 expression = "e + 8 - a + 5"
和一个求值映射,如 {"e": 1}
(给定的形式为 evalvars = ["e"]
和 evalints = [1]
),返回表示简化表达式的标记列表,例如 ["-1*a","14"]
- 表达式交替使用块和符号,每个块和符号之间有一个空格。
- 块要么是括号中的表达式,要么是变量,要么是非负整数。
- 变量是一个由小写字母组成的字符串(不包括数字)。请注意,变量可以是多个字母,并注意变量从不具有像
"2x"
或"-x"
这样的前导系数或一元运算符 。
表达式按通常顺序进行求值:先是括号,然后求乘法,再计算加法和减法。
- 例如,
expression = "1 + 2 * 3"
的答案是["7"]
。
输出格式如下:
- 对于系数非零的每个自变量项,我们按字典排序的顺序将自变量写在一个项中。
- 例如,我们永远不会写像
“b*a*c”
这样的项,只写“a*b*c”
。
- 例如,我们永远不会写像
- 项的次数等于被乘的自变量的数目,并计算重复项。我们先写出答案的最大次数项,用字典顺序打破关系,此时忽略词的前导系数。
- 例如,
"a*a*b*c"
的次数为 4。
- 例如,
- 项的前导系数直接放在左边,用星号将它与变量分隔开(如果存在的话)。前导系数 1 仍然要打印出来。
- 格式良好的一个示例答案是
["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c", "-6"]
。 - 系数为
0
的项(包括常数项)不包括在内。- 例如,
“0”
的表达式输出为[]
。
- 例如,
注意:你可以假设给定的表达式均有效。所有中间结果都在区间 [-231, 231 - 1]
内。
示例 1:
输入:expression = "e + 8 - a + 5", evalvars = ["e"], evalints = [1] 输出:["-1*a","14"]
示例 2:
输入:expression = "e - 8 + temperature - pressure", evalvars = ["e", "temperature"], evalints = [1, 12] 输出:["-1*pressure","5"]
示例 3:
输入:expression = "(e + 8) * (e - 8)", evalvars = [], evalints = [] 输出:["1*e*e","-64"]
提示:
1 <= expression.length <= 250
expression
由小写英文字母,数字'+'
,'-'
,'*'
,'('
,')'
,' '
组成expression
不包含任何前空格或后空格expression
中的所有符号都用一个空格隔开0 <= evalvars.length <= 100
1 <= evalvars[i].length <= 20
evalvars[i]
由小写英文字母组成evalints.length == evalvars.length
-100 <= evalints[i] <= 100