Code written by me, post generated by ChatGPT. Hope it'll help!
這題可以用 Two Stack (Shunting Yard) 演算法。
使用兩個 stack:
values stack 存數值
operators stack 存運算子
逐個讀 token:
直接 push 到 values stack。
vals.push(number)
(直接 push 到 operator stack。
opers.push('(')
)持續計算直到遇到 (:
while(opers.top() != '(')
reduce()
pop '('
假設新運算子為 op。
如果 stack top 的運算子優先度 大於等於 新運算子,就先計算:
while(
opers 不空 &&
opers.top() != '(' &&
precedence(top) >= precedence(op)
)
reduce()
然後 push 新運算子。
從 stack 取出兩個數字與一個 operator:
rhs = vals.top()
lhs = vals.top()
op = opers.top()
計算:
lhs op rhs
再 push 回 values stack。
當整行 token 讀完後:
while(opers 不空)
reduce()
stack 中剩下的值就是答案。
每個 token 最多 push / pop 一次:
O(n)
輸入
2 + ( 3 + 4 ) * 5
輸出
37
讀到 2
vals: [2]
opers: []
讀到 +
vals: [2]
opers: [+]
讀到 (
vals: [2]
opers: [+, (]
讀到 3
vals: [2, 3]
opers: [+, (]
讀到 +
vals: [2, 3]
opers: [+, (, +]
讀到 4
vals: [2, 3, 4]
opers: [+, (, +]
讀到 )
開始計算直到遇到 (:
3 + 4 = 7
vals: [2, 7]
opers: [+]
讀到 *
vals: [2, 7]
opers: [+, *]
讀到 5
vals: [2, 7, 5]
opers: [+, *]
最後清空 operator stack:
7 * 5 = 35
2 + 35 = 37
結果:
37
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int getPrec(char op){
if(op == '+' || op == '-')
return 1;
if(op == '*' || op == '/'|| op == '%')
return 2;
return 0;
}
ll doOper(ll a, ll b, char op){
switch(op){
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
case '%': return a % b;
}
throw runtime_error("Invalid op");
}
int main(){
stack<ll> vals;
stack<char> opers;
auto reduce = [&](){
char op = opers.top(); opers.pop();
ll rhs = vals.top(); vals.pop();
ll lhs = vals.top(); vals.pop();
vals.push(doOper(lhs, rhs, op));
};
string line;
while(getline(cin, line)){
vals = stack<ll>();
opers = stack<char>();
stringstream ss(line);
string token;
while(ss >> token){
char c = token[0];
if(isdigit(c)){
vals.push(stoll(token));
}
else if(c == '('){
opers.push('(');
}
else if(c == ')'){
while(opers.top() != '(')
reduce();
opers.pop();
}
else{
int prec = getPrec(c);
while(!opers.empty() &&
opers.top() != '(' &&
getPrec(opers.top()) >= prec)
reduce();
opers.push(c);
}
}
while(!opers.empty())
reduce();
cout << vals.top() << "\n";
}
}
這題本質是 expression parsing。
常見O(n)解法:
Two Stack / Shunting Yard (此題推)Recursive Descent
Pratt Parsing
LR Parsing