一、题目描述
给你一个字符串表达式 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 * 10^5
s
由数字、'+'
、'-'
、'('
、')'
、和' '
组成s
表示一个有效的表达式- '+' 不能用作一元运算(例如, "+1" 和
"+(2 + 3)"
无效) - '-' 可以用作一元运算(即 "-1" 和
"-(2 + 3)"
是有效的) - 输入中不存在两个连续的操作符
- 每个数字和运行的计算将适合于一个有符号的 32位 整数
二、解题思路
- 使用一个栈来存储操作数和一个变量来存储当前的计算结果。
- 使用一个变量
sign
来记录当前的符号,初始化为+
。 - 遍历字符串,对于每个字符:
- 如果是数字,则更新当前数字(可能有多位)。
- 如果是符号(
+
或-
)或者遇到括号,则将之前的数字(如果有)和符号计算进当前结果。 - 如果是左括号
(
,将当前结果和符号压入栈中,并重置为开始新的子表达式的计算。 - 如果是右括号
)
,则计算当前子表达式的结果,并从栈中弹出之前的符号和结果,继续计算。
- 在遍历结束后,将最后的数字(如果有)加到结果中。
三、具体代码
import java.util.Stack;
class Solution {
public int calculate(String s) {
Stack<Integer> stack = new Stack<>();
int result = 0;
int number = 0;
int sign = 1; // 1 for '+', -1 for '-'
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
number = number * 10 + (c - '0');
} else if (c == '+') {
result += sign * number;
sign = 1;
number = 0;
} else if (c == '-') {
result += sign * number;
sign = -1;
number = 0;
} else if (c == '(') {
// Push the result and sign on to the stack, then reset them
stack.push(result);
stack.push(sign);
// Reset the result and sign for the value in the parenthesis
result = 0;
sign = 1;
} else if (c == ')') {
// First number * sign
result += sign * number;
number = 0;
// Add the result from the parenthesis to the last result
result *= stack.pop(); // This should be the sign before the parenthesis
result += stack.pop(); // This should be the result calculated before the parenthesis
}
}
if (number != 0) {
result += sign * number;
}
return result;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 我们需要遍历字符串
s
一次,其长度为n
。 - 在遍历过程中,对于每个字符,我们执行常数时间的操作,如判断字符类型、计算数字、更新结果等。
- 因此,整个算法的时间复杂度为 O(n),其中 n 是字符串
s
的长度。
2. 空间复杂度
- 我们使用了一个栈
stack
来存储中间结果和符号。 - 在最坏的情况下,如果表达式
s
是一个嵌套很深的括号表达式,栈的大小可能会达到n
(即字符串的长度)。 - 因此,空间复杂度为 O(n),其中 n 是字符串
s
的长度。
五、总结知识点
-
基本数据类型:
int
:用于表示整数。char
:用于表示单个字符。
-
类和对象:
class Solution
:定义一个名为Solution
的类。new Stack<Integer>()
:创建Stack
类的实例,用于实现栈数据结构。
-
循环结构:
for
循环:用于遍历字符串中的每个字符。
-
条件判断:
if-else if-else
:用于根据不同的字符类型执行不同的操作。
-
字符串处理:
String.length()
:获取字符串的长度。String.charAt(int index)
:获取字符串中指定位置的字符。
-
字符操作:
Character.isDigit(char c)
:判断字符是否为数字。
-
数学运算:
- 算术运算:加法(
+
)、乘法(*
)、减法(-
)。 - 模运算:
c - '0'
,用于将字符数字转换为整数。
- 算术运算:加法(
-
栈操作:
Stack.push(E item)
:将元素压入栈顶。Stack.pop()
:移除栈顶元素并返回。
-
逻辑处理:
- 符号处理:根据符号
+
或-
更新计算结果。 - 括号处理:使用栈来处理嵌套的括号表达式。
- 符号处理:根据符号
-
算法思想:
- 使用栈来处理表达式中括号和运算符的优先级。
- 使用变量来存储中间计算结果和当前的操作符。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。