题目
我就口头描述一遍吧:把给出的表达式字符串计算它的算式结果并返回。其中表达式只含有:’+’、’-’、’*’、’/’、空格、数字。。。这些字符。
而对于表达式可能会出现:3+(2*-2) or 7+(-34+5)..
等特殊情况。
题目分析
对于这种算式计算我们一般采用双栈形式:
- 数字处理栈:用于存储表达式中的数字。
- 字符处理栈:用于存储各种运算符以及括号。
而我们如何处理这样一个计算过程呢?
- 预处理(去空格、数字栈预先置0、设置优先级、设置正负标记)
- 扫描到括号:
'('
则入栈,碰到')'
则开始出栈计算答案,直到遇到左括号。 - 扫描到数字或者字符:
对于数字,一旦扫描到一个数字的开头,就一直连续扫描到结尾进行数字更新,最后的结果再乘以符号标记。
对于字符,一旦扫描到字符后,字符串的前一个仍然是字符,则该字符只可能是代表数字的符号,所以此字符不入栈,仅仅作为更新数字符号的标记,其他情况就根据优先级判断上一个运算符的优先级是否大于等于当前的运算符,如果是,则开始计算答案。
如果到最后字符栈还有运算符则继续计算,直到为空
代码拆解
预处理
去空格
void preCond(string& s){
int i = s.find(' ');
while(i!=-1){
s.replace(i,1,"");
i = s.find(' ');
}
}
置0,设置优先级和符号标记(默认为正)
nums.push_back(0);
prior['+'] = prior['-'] = 1;
prior['*'] = prior['/'] = 2;
int syb = 1;
关键求值函数calc()
int calc(){
int b = nums.back();nums.pop_back();
int a = nums.back();nums.pop_back();
char op = ops.back();ops.pop_back();
switch(op){
case '+':return a+b;
case '-':return a-b;
case '*':return a*b;
case '/':return a/b;
}
return -1;
}
括号处理
//括号处理
if(op=='(') ops.push_back(op);
else if(op==')'){
while(!ops.empty()){
if(ops.back()!='(')
nums.push_back(calc());
else {
ops.pop_back();
break;
}
}
}
数字和字符处理
//数字和符号处理(碰到强行2*-3的情况,直接在入数字的时候入-3,符号'-'不要计入符号栈)
else{
if(isdigit(op)){
int j = i;
int num = 0;
while(isdigit(s[j])){
num = num*10 + (s[j++]-'0');
}
nums.push_back(num*syb);
syb = 1;
i = j-1;
}else{
if(i>0&& s[i-1]=='(' or s[i-1]=='*' or s[i-1]=='/' or s[i-1]=='+' or s[i-1]=='-'){
if(op=='-')syb = -1;
}
else{
while(!ops.empty()&&prior[ops.back()]>=prior[op]){
nums.push_back(calc());
}
ops.push_back(op);}
}
}
}
while(!ops.empty()){
nums.push_back(calc());
}
综合代码得出答案
还好效率还行!
class Solution {
public:
int calculate(string s) {
//预处理三件事:1.消除空格 2.防止最开始有符号设置了最开始0入栈 3.用数组设置优先级
preCond(s);
nums.push_back(0);
prior['+'] = prior['-'] = 1;
prior['*'] = prior['/'] = 2;
int syb = 1;
for(int i=0;i<s.size();i++){
char op = s[i];
//括号处理
if(op=='(') ops.push_back(op);
else if(op==')'){
while(!ops.empty()){
if(ops.back()!='(')
nums.push_back(calc());
else {
ops.pop_back();
break;
}
}
}
//数字和符号处理(碰到强行2*-3的情况,直接在入数字的时候入-3,符号'-'不要计入符号栈)
else{
if(isdigit(op)){
int j = i;
int num = 0;
while(isdigit(s[j])){
num = num*10 + (s[j++]-'0');
}
nums.push_back(num*syb);
syb = 1;
i = j-1;
}else{
if(i>0&& s[i-1]=='(' or s[i-1]=='*' or s[i-1]=='/' or s[i-1]=='+' or s[i-1]=='-'){
if(op=='-')syb = -1;
}
else{
while(!ops.empty()&&prior[ops.back()]>=prior[op]){
nums.push_back(calc());
}
ops.push_back(op);}
}
}
}
while(!ops.empty()){
nums.push_back(calc());
}
return nums.back();
}
private:
int prior[128] = {0};
vector<int>nums;
vector<char>ops;
int calc(){
int b = nums.back();nums.pop_back();
int a = nums.back();nums.pop_back();
char op = ops.back();ops.pop_back();
switch(op){
case '+':return a+b;
case '-':return a-b;
case '*':return a*b;
case '/':return a/b;
}
return -1;
}
void preCond(string& s){
int i = s.find(' ');
while(i!=-1){
s.replace(i,1,"");
i = s.find(' ');
}
}
};
```