给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。Given a string s representing an expression, implement a basic calculator to evaluate it.
示例
示例 1:
输入:s = "1 + 1"
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23
解题
https://zhuanlan.zhihu.com/p/115807632方法:栈和反转字符串 这个问题适合用栈来解决,因为表达式中包含括号,我们可以使用栈来查找每个子表达式的值。本质上,我们需要延迟处理主表达式,直到完成对括号种的中间子表达式的求值,我们使用栈来解决它。我们将表达式的元素一个接一个的添加到栈上,直到我们遇到一个右括号 )。然后逐个弹出栈中的元素,在运行时对子表达式进行求值,直到遇到左括号 ( 为止。我们需要理解 + 和 - 的区别。+ 遵循结合律。例如 [公式] ,等价于 [公式] 。然后 - 不遵循这个一规则,这是该方法中所有问题的根本原因。如果我们使用栈并从左到右读取表达式的元素,则最终我们会从右到左计算表达式。就会出现 [公式] 等于 [公式] 的情况,这是不正确的。减法即不遵循结合律也不遵循交换律。这个问题很容易解决,我们通过反转字符串,然后再按需添加到栈中,我们将字符串从右到左放入栈中,并从左到右正确的计算表达式。算法:按逆序迭代字符串。操作数可以由多个字符组成,字符串 "123" 表示数字 123,它可以被构造为:123 >> 120 + 3 >> 100 + 20 + 3。如果我们读取的字符是一个数字,则我们要将读取的数字乘以 10 的幂并将当前数字相加,形成操作数。因为我们是按逆序处理字符串。操作数由多个字符组成,一旦我们遇到的字符不是数字,则我们将操作数添加到栈上。当我们遇到最括号 (,这意味这遇到了一个子表达式结束。由于我们是逆序,所以开括号成了表达式的结尾。则需要从栈中弹出操作数和运算发来计算表达式,直到弹出相应的右括号。子表达式的最终结果最终添加到栈上。将非数字字符添加到栈上。这个做直到我们得到最终的结果。可能我们没有更多的字符要处理,但是栈仍然是非空的。当主表达式没有用括号括起来时,就会发生这种情况。因此,在完成对整个表达式求值之后,我们将检查栈是否非空。如果是的话,我们将栈中的元素作为最终表达式处理,并像遇到左括号时那样对其求值。我们还可以用一组括号覆盖原表达式,以此避免额外调用。
class Solution {
public int evaluateExpr(Stack<Object> stack) {
int res = 0;
if (!stack.empty()) {
res = (int) stack.pop();
}
// Evaluate the expression till we get corresponding ')'
while (!stack.empty() && !((char) stack.peek() == ')')) {
char sign = (char) stack.pop();
if (sign == '+') {
res += (int) stack.pop();
} else {
res -= (int) stack.pop();
}
}
return res;
}
public int calculate(String s) {
int operand = 0;
int n = 0;
Stack<Object> stack = new Stack<Object>();
for (int i = s.length() - 1; i >= 0; i--) {
char ch = s.charAt(i);
if (Character.isDigit(ch)) {
// Forming the operand - in reverse order.
operand = (int) Math.pow(10, n) * (int) (ch - '0') + operand;
n += 1;
} else if (ch != ' ') {
if (n != 0) {
// Save the operand on the stack
// As we encounter some non-digit.
stack.push(operand);
n = 0;
operand = 0;
}
if (ch == '(') {
int res = evaluateExpr(stack);
stack.pop();
// Append the evaluated result to the stack.
// This result could be of a sub-expression within the parenthesis.
stack.push(res);
} else {
// For other non-digits just push onto the stack.
stack.push(ch);
}
}
}
//Push the last operand to stack, if any.
if (n != 0) {
stack.push(operand);
}
// Evaluate any left overs in the stack.
return evaluateExpr(stack);
}
}