224. Basic Calculator
Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .
Example 1:
Input: "1 + 1"
Output: 2
Example 2:
Input: " 2-1 + 2 "
Output: 3
Example 3:
Input: "(1+(4+5+2)-3)+(6+8)"
Output: 23
Note:
You may assume that the given expression is always valid.
Do not use the eval built-in library function.
方法1:
laioffer: https://www.youtube.com/watch?v=9c0WHgIsk5g
思路:
首先考虑没有括号的情况:因为题目限制了只有加减,没有括号优先级从左到右。初始化用第一个数字,之后需要遍历所有字符,对每一个数字,记录它本身和它之前的符号,如果是‘-’就substract,如果是‘+’就add。
那么加上括号会改变什么?先进来的符号如果跟着parentheses就有可能被后执行。模拟先进后出需要借用stack。同时记录符号的优先级,1,2, 3, …,有左括号的话,将要进来的符号优先级++,右括号将未来的符号优先级–。所以对于一个operator/operand组合,我们要做的是:1. 用operand之前出现的一个operator来决定sign,往之前的result上累加。除非之前紧邻的是一个“(”, sign恢复默认值1,先不要累加。2. 每当遇到了“(”,我们将前一个operator入栈,sign = 1, 并将之前的result推入另一个栈,result清零。3. 每当遇到了“)", 说明后面的优先级降低,此时由于遵从由左到右的顺序,operator栈顶如果不为空将有更高优先级,同时从operator栈中pop符号,从operand栈中pop数字继续累加。
在这个过程中operand和operator由两个栈来维护并始终保持着同样的大小,每次需同时弹入弹出。
优先级这个信息并不需要直白的记录,可以用以下方法,由“(”,“)”,两个条件段自动控制优先级。
易错点
- 数字可以不止一位,即使栗子里面故意不提醒你。所以需要一个单独的变量num用来累计连续数字。这个数字只有当遇到下一个不为数字的字符时,可以当作结果被累计。
- 注意“)”这个段落及其容易错,此时的op.top()到底是谁的operator?是在result被清零前被入栈的,因此属于当前括号内累加的结果result。这个result * op.top() 应该向谁继续累加?和op.top()被同时推入栈的上一个result,也就是当前的od.top()。而且取出后别忘弹栈。
- 最后一次result += sign * num 为什么重要:当expression以non-digit结尾(反括号或者whitespace),最后一个operand没有机会进入else去累加到结果上。
- (c - ‘0’)这个地方括号也很重要:如果input就是INT_MAX,上来直接加c会overflow。
Complexity
Time complexity: O(n)
Space complexity: O(n)
class Solution {
public:
int calculate(string s) {
int result = 0;
int sign = 1;
int num = 0;
stack<int> op;
stack<int> od;
for (char c: s){
if (isdigit(c)){
num = num * 10 + (c - '0');
}
else {
result += sign * num;
num = 0;
if (c == '+'){
sign = 1;
}
else if (c == '-'){
sign = -1;
}
else if (c == '('){
op.push(sign);
od.push(result);
sign = 1;
result = 0;
}
else if (c == ')'){
// 5 = 10 - (5 * 1)
// 5 = - (5 * 1) + 10
result = result* op.top() + od.top();
op.pop();
od.pop();
}
}
}
result += sign * num;
return result;
}
};
// "(1+(4+5+2)-3)+(6+8)"
// i
//result = 9
// sign = -1
// op = {1, }
// od = {0, }
方法2: recursion
参考 772. Basic Calculator III
grandyang: http://www.cnblogs.com/grandyang/p/4570699.html