int operatorPrecedence(char ch)
{
struct opPD
{
char _op;
int _pd;
};
static opPD arr[] = { {'+', 1},{'-', 1},{'*', 2},{'/', 2} };
for (auto& e : arr)
{
if (e._op == ch)
{
return e._pd;
}
}
assert(false);
return -1;
}
2. 中缀转后缀
cpp复制代码
void toRPN(const string& s, size_t& i, vector<string>& v)
{
stack<char> st;
while (i < s.size())
{
if (isdigit(s[i]))
{
// 运算数输出
string num;
while (i < s.size() && isdigit(s[i]))
{
num += s[i];
++i;
}
v.push_back(num);
}
else
{
if (s[i] == '(')
{
// 递归⽅式处理括号中的⼦表达式
++i;
toRPN(s, i, v);
}
else if (s[i] == ')')
{
++i;
//栈中的运算符全部输出
while (!st.empty())
{
v.push_back(string(1, st.top()));
st.pop();
}
// 结束递归
return;
}
else
{
// 1、如果栈为空或者栈不为空且当前运算符⽐栈顶运算符优先级⾼,则当前运算符⼊栈
// 2、如果栈不为为空且⽐栈顶运算符优先级低或相等,说明栈顶的运算符可以运算了,
// 3、输出栈顶运算符,当前运算符继续⾛前⾯遇到运算符的逻辑
if (st.empty() || operatorPrecedence(s[i])>operatorPrecedence(st.top()))
{
st.push(s[i]);
++i;
}
else
{
v.push_back(string(1, st.top()));
st.pop();
}
}
}
}
// 栈中的运算符全部输出
while (!st.empty())
{
v.push_back(string(1, st.top()));
st.pop();
}
}
3. 后缀运算
cpp复制代码
int evalRPN(const vector<string>& tokens) {
stack<long long> s;
for (size_t i = 0; i < tokens.size(); ++i)
{
const string& str = tokens[i];
// str为数字
if (!("+" == str || "-" == str || "*" == str || "/" == str))
{
s.push(stoll(str));
}
else
{
// str为操作符
long long right = s.top();
s.pop();
long long left = s.top();
s.pop();
// 运算符
switch (str[0])
{
case '+':
s.push(left + right);
break;
case '-':
s.push(left - right);
break;
case '*':
s.push(left * right);
break;
case '/':
s.push(left / right);
break;
}
}
}
return s.top();
}
4. 详细代码
cpp复制代码
class Solution {
public:
int operatorPrecedence(char ch)
{
struct opPD
{
char _op;
int _pd;
};
static opPD arr[] = { {'+', 1},{'-', 1},{'*', 2},{'/', 2} };
for (auto& e : arr)
{
if (e._op == ch)
{
return e._pd;
}
}
assert(false);
return -1;
}
void toRPN(const string& s, size_t& i, vector<string>& v)
{
stack<char> st;
while (i < s.size())
{
if (isdigit(s[i]))
{
// 运算数输出
string num;
while (i < s.size() && isdigit(s[i]))
{
num += s[i];
++i;
}
v.push_back(num);
}
else
{
if (s[i] == '(')
{
// 递归⽅式处理括号中的⼦表达式
++i;
toRPN(s, i, v);
}
else if (s[i] == ')')
{
++i;
//栈中的运算符全部输出
while (!st.empty())
{
v.push_back(string(1, st.top()));
st.pop();
}
// 结束递归
return;
}
else
{// 1、如果栈为空或者栈不为空且当前运算符⽐栈顶运算符优先级⾼,则当前运算符⼊栈
// 2、如果栈不为为空且⽐栈顶运算符优先级低或相等,说明栈顶的运算符可以运算了,
// 输出栈顶运算符,当前运算符继续⾛前⾯遇到运算符的逻辑
if (st.empty() || operatorPrecedence(s[i]) > operatorPrecedence(st.top()))
{
st.push(s[i]);
++i;
}
else
{
v.push_back(string(1, st.top()));
st.pop();
}
}
}
}
// 栈中的运算符全部输出
while (!st.empty())
{
v.push_back(string(1, st.top()));
st.pop();
}
}
int evalRPN(const vector<string>& tokens) {
stack<long long> s;
for (size_t i = 0; i < tokens.size(); ++i)
{
const string& str = tokens[i];
// str为数字
if (!("+" == str || "-" == str || "*" == str || "/" == str))
{
s.push(stoll(str));
}
else
{
// str为操作符
long long right = s.top();
s.pop();
long long left = s.top();
s.pop();
// 运算符
switch (str[0])
{
case '+':
s.push(left + right);
break;
case '-':
s.push(left - right);
break;
case '*':
s.push(left * right);
break;
case '/':
s.push(left / right);
break;
}
}
}
return s.top();
}
int calculate(string s) {
// 1、去除所有空格,否则下⾯的⼀些逻辑没办法处理
std::string news;
news.reserve(s.size());
for (auto ch : s)
{
if (ch != ' ')
news += ch;
}
s.swap(news);
news.clear();
// 2、将所有的负数-x转换为0-x
for (size_t i = 0; i < s.size(); ++i)
{
if (s[i] == '-' && (i == 0 || (!isdigit(s[i - 1]) && s[i - 1] != ')')))
news += "0-";
else
news += s[i];
}
size_t i = 0;
vector<string> v;
// 后缀表达式进⾏运算
toRPN(news, i, v);
return evalRPN(v);
// 中缀表达式转成后缀表达式
}
};
方法二:(处理括号+用栈判断括号内运算符)
详细代码:
cpp复制代码
class Solution {
public:
int calculate(string s) {
int ans = 0, sign = 1, i = 0, n = s.size();
stack<int> stk;
stk.push(1);
while (i < n) {
if (s[i] == ' ') ++i;
else if (s[i] == '+') {
sign = stk.top();
++i;
}
else if (s[i] == '-') {
sign = -stk.top();
++i;
}
else if (s[i] == '(') {
stk.push(sign);
++i;
}
else if (s[i] == ')') {
stk.pop();
++i;
}
else {
long num = 0;
while (i < n && '0' <= s[i] && s[i] <= '9') {
num = num * 10 + s[i] - '0';
++i;
}
ans += sign * num;
}
}
return ans;
}
};
方法三:(用栈存储正负数据)
详细代码:
cpp复制代码
int calculate(string s) {
stack<int> stk;
// 记录算式中的数字
int num = 0;
// 记录 num 前的符号,初始化为 +
char sign = '+';
for (int i = 0; i < s.size(); i++) {
char c = s[i];
// 如果是数字,连续读取到 num
if (isdigit(c))
num = 10 * num + (c - '0');
// 如果不是数字,就是遇到了下一个符号,
// 之前的数字和符号就要存进栈中
if (!isdigit(c) || i == s.size() - 1) {
switch (sign) {
case '+':
stk.push(num); break;
case '-':
stk.push(-num); break;
}
// 更新符号为当前符号,数字清零
sign = c;
num = 0;
}
}
// 将栈中所有结果求和就是答案
int res = 0;
while (!stk.empty()) {
res += stk.top();
stk.pop();
}
return res;
}
扩展:(乘除法)
cpp复制代码
for (int i = 0; i < s.size(); i++) {
char c = s[i];
if (isdigit(c))
num = 10 * num + (c - '0');
if (!isdigit(c) || i == s.size() - 1) {
switch (sign) {
int pre;
case '+':
stk.push(num); break;
case '-':
stk.push(-num); break;
// 只要拿出前一个数字做对应运算即可
case '*':
pre = stk.top();
stk.pop();
stk.push(pre * num);
break;
case '/':
pre = stk.top();
stk.pop();
stk.push(pre / num);
break;
}
// 更新符号为当前符号,数字清零
sign = c;
num = 0;
}
}