一.题意整理
给出一个含有加减乘除和括号的表达式的字符串,求出该字符串的值。(运算符合运算法则,先乘除后加减)
二.思路整理
利用栈来求表达式是栈的一种基本运用,下面我们将会介绍如何利用栈来解决表达式求值的问题:
对于算术表达式一般分成三种有:前缀、后缀和中缀
中缀表达式:救是我们常见的算术表达式,就是一眼看上去就能理解的表达式,例如:2*(5+8)
前缀表达式:形如"op A B"即操作数在两个运算数的前面
后缀表达式:形如"A B op"即操作数在两个运算数的后面
下面给出计算表达式的核心思路:对于一个表达式,也就是对于一个中缀表达式我们可以先将表达式转换成后缀表达式,然后对这个后缀表达式求值。
中缀表达数转后缀表达式:
1.建立一个存储运算符的栈,对中缀表达式进行扫描。
(1)如果遇到一个数就直接存进后缀表达式中。
(2)如果遇到了一个左括号,就把左括号直接入栈。
(3)如果遇到右括号,不断取出栈顶并输出,直到栈顶为左括号,然后左括号出栈。
(4)如果遇到运算符,只需要栈顶符号的优先级补丁与新符号,就不断出栈并输出,然后将新符号入栈。
2.依次取出并存储栈中所有剩余的符号。
后缀表达式求值:
1.建立一个用于存储的数的栈,对后缀表达式进行依次扫描
(1)如果遇见一个数,那么就把这个数直接入栈
(2)如果遇到运算符,就取出栈顶的两个数进行计算,然后把结果入栈。
2.最后的栈顶元素就是表达式的值
三.代码实现
class Solution {
public:
int solve(string s) {
/*
为什么这块要用string 而不是char?
只用利用结点为string的vecter可以方便的表示字符和数字
对于式数字的string可以利用stoi函数来进行转换
*/
unordered_map<string,int>mp;//用来记录优先级
mp["*"]=1;
mp["+"]=0;
mp["+"]=0;
stack<string>op;//中缀表达式转化为后缀表达式中符号栈
stack<int>num;//后缀表达式求值中需要的数字栈
string str="";
vector<string>ss;//后缀表达式
//中缀表达式转换为后缀表达式
for(int i=0;i<s.size();i++){
if(!isdigit(s[i])){
if(str!=""){
ss.push_back(str);
str="";
}
}
if(isdigit(s[i])){
str+=s[i];
} else {
if(s[i]=='('){
string now="";
now+=s[i];
op.push(now);
} else if(s[i]==')'){
while(op.size()&&op.top()!="("){
ss.push_back(op.top());
op.pop();
}
op.pop();
} else {
string now="";
now+=s[i];
while(op.size()&&op.top()!="("&&mp[now]<=mp[op.top()]){
ss.push_back(op.top());
op.pop();
}
now="";
now+=s[i];
op.push(now);
}
}
}
if(str!="") ss.push_back(str);
while(op.size()){
ss.push_back(op.top());
op.pop();
}
//后缀表达式求值
for(int i=0;i<ss.size();i++){
if(ss[i]=="+"){
int a=num.top();
num.pop();
int b=num.top();
num.pop();
num.push(a+b);
} else if(ss[i]=="-"){
int a=num.top();
num.pop();
int b=num.top();
num.pop();
num.push(b-a);
} else if(ss[i]=="*"){
int a=num.top();
num.pop();
int b=num.top();
num.pop();
num.push(a*b);
} else {
num.push(stoi(ss[i]));
}
}
//返回表达式的值
return num.top();
}
};