题目描述
请实现一个简易计算器,计算一个算数表达式的值。
表达式中仅包含左括号(
、右括号)
、加号+
、减号-
、非负整数 和空格。
注意:
- 所有表达式都是合法的;
- 不能使用内建函数
eval
来计算表达式的值;
样例1
输入:"1 + 1"
输出:2
样例2
输入:" 2-1 + 2 "
输出:3
样例3
输入;"(1+(4+5+2)-3)+(6+8)"
输出:23
算法
(栈,表达式求值) $O(n)$
开两个栈,一个记录数字,一个记录操作符。
然后从前往后扫描整个表达式:
- 如果遇到
(
、+
、-
,直接入栈; - 如果遇到数字,则判断操作符栈的栈顶元素,如果不是
(
,则弹出操作符的栈顶元素,并用相应操作更新数字栈的栈顶元素。从而保证操作符栈的栈顶最多有一个连续的+
或-
; - 如果遇到
)
,此时操作符栈顶一定是(
,将其弹出。然后根据新栈顶的操作符,对数字栈顶的两个元素进行相应操作;
时间复杂度分析:每个数字和操作进栈出栈一次,所以总时间复杂度是 $O(n)$。
C++ 代码
class Solution {
public:
void calc(stack<char> &op, stack<int> &num) {
int y = num.top();
num.pop();
int x = num.top();
num.pop();
if (op.top() == '+') num.push(x + y);
else num.push(x - y);
op.pop();
}
int calculate(string s) {
stack<char> op;
stack<int> num;
for (int i = 0; i < s.size(); i ++ ) {
char c = s[i];
if (c == ' ') continue;
if (c == '+' || c == '-' || c == '(') op.push(c);
else if (c == ')') {
op.pop();
if (op.size() && op.top() != '(') {
calc(op, num);
}
}
else {
int j = i;
while (j < s.size() && isdigit(s[j])) j ++ ;
num.push(atoi(s.substr(i, j - i).c_str()));
i = j - 1;
if (op.size() && op.top() != '(') {
calc(op, num);
}
}
}
return num.top();
}
};
可以 ac的版本.加了一个小的改动.就是判定是否需要zero. 都是在特定位置才需要补零的.
class Solution {
public:
};
2022-05-08可通过的代码:
用
is_neg
标示一下接下来读到的-
是否表示负号
的含义,取负操作只可能出现在表达式开头或紧挨着(
,每次读入一个字符后根据是否为(
更新一下is_neg
即可如果读到了
负号
含义的-
,补一个0
在操作数中即可,其余时候不需要额外操作leetcode加测试了,y总的代码现在过不了
目前我没看到一个能完整过的,
现在最新的模版是什么
感觉新加的test case有捣乱之嫌,就是在正数前面加+
在正数前面加‘-’吧
LeetCode上增加了测试样例,对y总的代码稍微改动一下就可以通过了。
leetcode上的测试数据加强了,需要在压入运算符前判断有没有操作数,如果没有,要压入0
比如有一个测试数据是
"-2+ 1"
或者不用判断,上来初始化数值栈的时候先压入一个0,反正这道题只有加减运算,0不影响
有如下例子
$1-(+1+1)$
如果( 后面不是数字的话,那么有几个运算符就要加上几个0。
但是目前的case只有多一个运算符,最多加一个0
看了你的回复,得到了帮助,谢谢。
这样是不行的。
为什么不用stoi(s.substr(i, j - i)),请教一下。谢谢
两种写法都可以。