写的第二道hardQAQ菜鸡落泪,感觉写的太复杂了,先写下自己的思路
思路:
直接用中缀表达式计算比较困难,一般先转成后缀表达式后计算
后缀表达式计算参考Leetcode上150.逆波兰表达式求值
中缀表达式转后缀表达式方法:
如果遇到一个数,则输出该数
如果遇到左括号,把左括号入栈
如果遇到右括号,不断取出栈顶并输出,直到栈顶为左括号,然后把左括号出栈
如果遇到运算符,只要栈顶运算符优先级>=新符号,就不断取出栈顶并输出,最后把新符号进栈,优先级顺序为乘除号>加减号>左括号
最后依次取出并输出栈中所有剩余符号,最终输出的就是与原中缀表达式等价的后缀表达式,再对后缀表达式求值。
如何判断运算符是加减法还是正负号?
将所有负数前面加0,变成0-x
时间复杂度O(n)
class Solution {
public:
bool isNumber(string s){
return !(s=="+"||s=="-"||s=="*"||s=="/");
}
bool isNotOp(char c){
return !(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')');
}
int calculate(string s) {
vector<string>str=toRPN(s);
// for(auto t:str){
// printf("%s\n",t.c_str());
// }
int res=calc(str);
return res;
}
//计算后缀表达式的值
int calc(vector<string> str){
stack<int>ans;
for(auto s:str){
if(isNumber(s)){
ans.push(atoi(s.c_str()));
}else{
int a=ans.top();
ans.pop();
int b=ans.top();
ans.pop();
if(s=="+"){
ans.push(b+a);
}else if(s=="-"){
ans.push(b-a);
}else if(s=="*"){
ans.push(b*a);
}else if(s=="/"){
ans.push(b/a);
}
}
}
return ans.top();
}
//操作符优先级
int opPower(char op){
if(op=='*'||op=='/')return 3;
else if(op=='+'||op=='-')return 2;
else return 1;
}
//将中缀表达式转为后缀表达式
vector<string> toRPN(string s){
int len=s.length();
stack<char>op;
vector<string>ans;
bool need_zero=false;
for(int i=0;i<len;i++){
//-2+1
if(i==0&&s[0]=='-')ans.push_back(to_string(0));
if(s[i]==' ')continue;
if(isNotOp(s[i])){
int num=0;
while(i<len&&isNotOp(s[i])&&s[i]!=' '){
num=num*10+(int)(s[i]-'0');
i++;
}
ans.push_back(to_string(num));
i--;
need_zero=false;
}else if(s[i]=='('){
op.push(s[i]);
need_zero=true;
}else if(s[i]==')'){
while(op.top()!='('){
ans.push_back(string(1,op.top()));
op.pop();
}
op.pop();
need_zero=false;
}else{
if(need_zero)ans.push_back(to_string(0));
while(!op.empty()&&opPower(s[i])<=opPower(op.top())){
ans.push_back(string(1,op.top()));
op.pop();
}
op.push(s[i]);
}
}
while(op.size()){
ans.push_back(string(1,op.top()));
op.pop();
}
return ans;
}
};